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
+702
View File
@@ -0,0 +1,702 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TC = System.ComponentModel.TypeConverterAttribute;
using EXP = System.ComponentModel.ExpandableObjectConverter;
namespace CodeWalker.GameFiles
{
[TC(typeof(EXP))]public class AwcFile : PackedFile
{
public string Name { get; set; }
public RpfFileEntry FileEntry { get; set; }
public byte[] Data { get; set; }
public string ErrorMessage { get; set; }
public uint Magic { get; set; }
public ushort Version { get; set; }
public ushort Flags { get; set; }
public int StreamCount { get; set; }
public int InfoOffset { get; set; }
public bool MultiChannel { get; set; }
public byte[] MultiChannelData { get; set; }
public AwcStreamInfo[] StreamInfos { get; set; }
public uint[] AudioIds { get; set; }
public AwcAudio[] Audios { get; set; }
public void Load(byte[] data, RpfFileEntry entry)
{
//adapted from libertyV code
//MemoryStream ms = new MemoryStream(data);
Name = entry.Name;
FileEntry = entry;
Data = data;
if ((data == null) || (data.Length < 8))
{
ErrorMessage = "Data null or too short!";
return; //nothing to do, not enough data...
}
Magic = BitConverter.ToUInt32(data, 0);
Endianess endianess = Endianess.LittleEndian;
switch (Magic)
{
default:
ErrorMessage = "Unexpected Magic 0x" + Magic.ToString("X");
return;
case 0x54414441:
endianess = Endianess.LittleEndian;
break;
case 0x41444154:
endianess = Endianess.BigEndian;
break;
}
using (MemoryStream ms = new MemoryStream(data))
{
DataReader r = new DataReader(ms, endianess);
Magic = r.ReadUInt32();
Version = r.ReadUInt16();
Flags = r.ReadUInt16();
StreamCount = r.ReadInt32();
InfoOffset = r.ReadInt32();
//notes from libertyV:
// first bit - means that there are unknown word for each stream after this header
// second bit - I think that it means that not all the tags are in the start of the file, but all the tags of a stream are near the data tag
// third bit - Multi channel audio
if ((Flags >> 8) != 0xFF)
{
ErrorMessage = "Flags 0 not supported!";
return;
}
if ((Flags & 0xF8) != 0)
{
//ErrorMessage = "Flags 1 not supported!";
//return;
}
MultiChannel = ((Flags & 4) == 4);
var flag0 = ((Flags & 1) == 1);
var infoStart = 16 + (flag0 ? (StreamCount * 2) : 0);
ms.Position = infoStart;
List<AwcStreamInfo> infos = new List<AwcStreamInfo>();
Dictionary<uint, AwcStreamInfo> infoDict = new Dictionary<uint, AwcStreamInfo>();
List<uint> audioIds = new List<uint>();
List<AwcAudio> audios = new List<AwcAudio>();
for (int i = 0; i < StreamCount; i++)
{
var info = new AwcStreamInfo(r);
infos.Add(info);
infoDict[info.Id] = info;
}
for (int i = 0; i < StreamCount; i++)
{
var info = infos[i];
for (int j = 0; j < info.TagCount; j++)
{
var chunk = new AwcChunkInfo(r);
info.Chunks[chunk.Tag] = chunk;
}
}
StreamInfos = infos.ToArray();
byte hformat = 0xFA;// 250 0x6061D4FA & 0xFF; //JenkHash.GenHash("format");
byte hdata = 0x55;// 85 0x5EB5E655 & 0xFF; //JenkHash.GenHash("data");
byte hycd = 0x5C;// 92 YCD resource chunk... lip sync anims?
byte hunk = 0x36;// 54 unk chunk? small number of bytes (2+)
if (MultiChannel)
{
AwcStreamInfo stream0 = null;
if (!infoDict.TryGetValue(0, out stream0))
{
ErrorMessage = "Couldn't find MultiChannel stream0";
return;
}
AwcChunkInfo chunk72 = null;
if (!stream0.Chunks.TryGetValue(72, out chunk72))
{
ErrorMessage = "Couldn't find MultiChannel chunk72";
return;
}
ms.Position = chunk72.Offset;
AwcChannelChunkInfo chanInfo = new AwcChannelChunkInfo(r);
if (chanInfo.ChannelCount != StreamCount - 1)
{
ErrorMessage = "Channel Count did not match Stream Count";
return;
}
List<AwcChannelChunkItemInfo> chunkItems = new List<AwcChannelChunkItemInfo>();
for (int i = 0; i < chanInfo.ChannelCount; i++)
{
var itemInfo = new AwcChannelChunkItemInfo(r);
chunkItems.Add(itemInfo);
audioIds.Add(infos[i + 1].Id);
}
//AudioStreams.Add(new MultiChannelAudio(new ChunkStream(this.Stream, streamsChunks[0][Tag("data")]), channelsInfoHeader, streamsInfo, header.BigEndian));
AwcChunkInfo cdata = null;
if (!stream0.Chunks.TryGetValue(hdata, out cdata))
{
ErrorMessage = "Couldn't find Stream 0 data chunk";
return;
}
ms.Position = cdata.Offset;
var lastPos = cdata.Offset + cdata.Size;
//int chunkSize = 0x800;
uint bigChunkSize = chanInfo.ChunkSize;
var chanCount = chanInfo.ChannelCount;
MultiChannelData = r.ReadBytes(cdata.Size);
ms.Position = cdata.Offset;
//var d = data;//temporary
////this doesn't seem to work :(
//while (ms.Position < lastPos)
//{
// uint totalChunks = 0;
// var startPos = ms.Position;
// var curPos = startPos;
// //byte[] chunkdata = r.ReadBytes(chunkSize);
// //ms.Position = startPos;
// AwcChannelChunkHeader[] chanHeaders = new AwcChannelChunkHeader[chanCount];
// for (int i = 0; i < chanCount; i++)
// {
// var chanHeader = new AwcChannelChunkHeader(r);
// chanHeaders[i] = chanHeader;
// totalChunks += chanHeader.ChunkCount;
// }
// int headerSize = (int)(totalChunks * 4 + chanInfo.ChannelCount * AwcChannelChunkHeader.Size);
// headerSize += (((-headerSize) % chunkSize) + chunkSize) % chunkSize; //todo: simplify this!
// curPos += headerSize;
// AwcChannelChunk[] chanChunks = new AwcChannelChunk[chanCount];
// for (int i = 0; i < chanCount; i++)
// {
// var chanChunk = new AwcChannelChunk(r, chanHeaders[i], chunkItems[i]);
// chanChunks[i] = chanChunk;
// curPos += chanChunk.TotalDataSize;
// }
// if (curPos - startPos > chanInfo.ChunkSize)
// {
// ErrorMessage = "Chunk was bigger than the chunk size";
// break;
// }
// if ((totalChunks == 0) || ((startPos + chanInfo.ChunkSize) > lastPos))
// {
// ErrorMessage = "Unable to read chunk";
// break;
// }
// var newPos = startPos + bigChunkSize;
// if (newPos >= lastPos) break;
// ms.Position = newPos;
//}
}
else
{
for (int i = 0; i < StreamCount; i++)
{
var info = infos[i];
AwcChunkInfo cformat = null;
if (!info.Chunks.TryGetValue(hformat, out cformat))
{
ErrorMessage = "Couldn't find Stream " + i.ToString() + " format chunk";
continue;
}
AwcChunkInfo cdata = null;
if (!info.Chunks.TryGetValue(hdata, out cdata))
{
ErrorMessage = "Couldn't find Stream " + i.ToString() + " data chunk";
continue;
}
AwcChunkInfo cycd = null;
AwcAudioAnimClipDict oycd = null;
if (info.Chunks.TryGetValue(hycd, out cycd))
{
ms.Position = cycd.Offset;
oycd = new AwcAudioAnimClipDict(r, cycd);
}
AwcChunkInfo cunk = null;
AwcAudioUnk ounk = null;
if (info.Chunks.TryGetValue(hunk, out cunk))
{
ms.Position = cunk.Offset;
ounk = new AwcAudioUnk(r, cunk);
}
ms.Position = cformat.Offset;
AwcFormatChunk formatChunk = new AwcFormatChunk(r);
ms.Position = cdata.Offset;
AwcAudio audio = new AwcAudio(r, info, formatChunk, cdata);
audio.ClipDict = oycd;
audio.UnkData = ounk;
audios.Add(audio);
audioIds.Add(info.Id);
}
}
Audios = audios.ToArray();
AudioIds = audioIds.ToArray();
}
}
}
[TC(typeof(EXP))] public class AwcStreamInfo
{
public uint RawVal { get; set; }
public uint TagCount { get; set; }
public uint Id { get; set; }
public Dictionary<byte, AwcChunkInfo> Chunks { get; set; } = new Dictionary<byte, AwcChunkInfo>();
public AwcStreamInfo(DataReader r)
{
RawVal = r.ReadUInt32();
TagCount = (RawVal >> 29);
Id = (RawVal & 0x1FFFFFFF);
}
public override string ToString()
{
return Id.ToString("X") + ": " + TagCount.ToString() + " tags";
}
}
[TC(typeof(EXP))] public class AwcChunkInfo
{
public ulong RawVal { get; set; }
public byte Tag { get; set; }
public int Size { get; set; }
public int Offset { get; set; }
public AwcChunkInfo(DataReader r)
{
RawVal = r.ReadUInt64();
Tag = (byte)(RawVal >> 56);
Size = (int)((RawVal >> 28) & 0x0FFFFFFF);
Offset = (int)(RawVal & 0x0FFFFFFF);
}
public override string ToString()
{
return Tag.ToString() + ": " + Size.ToString() + ", " + Offset.ToString();
}
}
[TC(typeof(EXP))] public class AwcChannelChunkInfo
{
public uint Unk0 { get; set; }
public uint ChunkSize { get; set; }
public uint ChannelCount { get; set; }
public AwcChannelChunkInfo(DataReader r)
{
Unk0 = r.ReadUInt32();
ChunkSize = r.ReadUInt32();
ChannelCount = r.ReadUInt32();
}
public override string ToString()
{
return Unk0.ToString() + ": " + ChunkSize.ToString() + ", " + ChannelCount.ToString() + " channels";
}
}
[TC(typeof(EXP))] public class AwcChannelChunkItemInfo
{
public uint Id { get; set; }
public uint Samples { get; set; }
public ushort Unk0 { get; set; }
public ushort SamplesPerSecond { get; set; }
public byte Unk1 { get; set; }
public byte RoundSize { get; set; }
public ushort Unk2 { get; set; }
public AwcChannelChunkItemInfo(DataReader r)
{
Id = r.ReadUInt32();
Samples = r.ReadUInt32();
Unk0 = r.ReadUInt16();
SamplesPerSecond = r.ReadUInt16();
Unk1 = r.ReadByte();
RoundSize = r.ReadByte();
Unk2 = r.ReadUInt16();
}
public override string ToString()
{
return Id.ToString() + ": " + Samples.ToString() + " samples, " + SamplesPerSecond.ToString() + " samples/sec, size: " + RoundSize.ToString();
}
}
[TC(typeof(EXP))] public class AwcFormatChunk
{
public uint Samples { get; set; }
public int UnkMinusOne { get; set; }
public ushort SamplesPerSecond { get; set; }
public ushort Unk1 { get; set; }
public ushort Unk2 { get; set; }
public ushort Unk3 { get; set; }
public ushort Unk4 { get; set; }
public byte Unk5 { get; set; }
public byte Unk6 { get; set; }
public AwcFormatChunk(DataReader r)
{
Samples = r.ReadUInt32();
UnkMinusOne = r.ReadInt32();
SamplesPerSecond = r.ReadUInt16();
Unk1 = r.ReadUInt16();
Unk2 = r.ReadUInt16();
Unk3 = r.ReadUInt16();
Unk4 = r.ReadUInt16();
Unk5 = r.ReadByte();
Unk6 = r.ReadByte();
//Apparently sometimes this struct is longer? TODO: fix??
//r.ReadUInt16();
//r.ReadUInt16();
}
public override string ToString()
{
return Unk1.ToString() + ", " + Unk6.ToString() + ": " + Samples.ToString() + " samples, " + SamplesPerSecond.ToString() + " samples/sec";
}
}
[TC(typeof(EXP))] public class AwcAudio
{
public AwcStreamInfo StreamInfo { get; set; }
public AwcFormatChunk Format { get; set; }
public AwcChunkInfo DataInfo { get; set; }
public byte[] Data { get; set; }
public AwcAudioAnimClipDict ClipDict { get; set; }
public AwcAudioUnk UnkData { get; set; }
public short Channels = 1;
public short BitsPerSample = 4;//16;
public int SamplesPerSecond
{
get
{
return Format?.SamplesPerSecond ?? 0;
}
}
public int SampleCount
{
get
{
return (int)(Format?.Samples ?? 0);
}
}
public string Name
{
get
{
return "0x" + StreamInfo?.Id.ToString("X").PadLeft(8, '0') ?? "0";
}
}
public string Type
{
get
{
if (Format == null) return "Unknown";
string fmt = "ADPCM";
switch (Format.Unk6)
{
case 4:
break;
default:
break;
}
var hz = Format?.SamplesPerSecond ?? 0;
return fmt + ((hz > 0) ? (", " + hz.ToString() + " Hz") : "");
}
}
public string LengthStr
{
get
{
if (Format == null) return "0:00";
float sec = (float)Format.Samples / Format.SamplesPerSecond;
TimeSpan ts = TimeSpan.FromSeconds(sec);
return ts.ToString("m\\:ss");
}
}
public AwcAudio(DataReader r, AwcStreamInfo s, AwcFormatChunk f, AwcChunkInfo d)
{
StreamInfo = s;
Format = f;
DataInfo = d;
Data = r.ReadBytes(d.Size);
}
public override string ToString()
{
var hash = (StreamInfo?.Id.ToString("X") ?? "0").PadLeft(8, '0');
return "0x" + hash + ": " + Format?.ToString() ?? "AwcAudio";
}
public Stream GetWavStream()
{
MemoryStream ms = new MemoryStream();
BinaryWriter w = new BinaryWriter(ms);
//see http://icculus.org/SDL_sound/downloads/external_documentation/wavecomp.htm
//see https://github.com/naudio/NAudio/blob/master/NAudio/Wave/WaveFormats/AdpcmWaveFormat.cs
//see https://msdn.microsoft.com/en-us/library/windows/desktop/ff538799(v=vs.85).aspx
int sampleCount = SampleCount;
int samplesPerSec = SamplesPerSecond;
//short sampleSize = (short)((BitsPerSample / 8) * Channels);//2
//int avgBytesPerSec = sampleSize * samplesPerSec;
short blockAlign = 512;
short samplesPerBlock = (short)((((blockAlign - (7 * Channels)) * 8) / (BitsPerSample * Channels)) + 2);
int avgBytesPerSec = ((samplesPerSec / samplesPerBlock) * blockAlign);
w.Write("RIFF".ToCharArray());
w.Write(0); //file size written later...
w.Write("WAVE".ToCharArray());
w.Write("fmt ".ToCharArray());
w.Write(50); //(PCM:16) //header size
w.Write((short)2); //pcm format tag 1=PCM, 2=ADPCM
w.Write(Channels);
w.Write(samplesPerSec);
w.Write(avgBytesPerSec);
w.Write(blockAlign);// sampleSize);
w.Write(BitsPerSample);
w.Write((short)32);//extra byte count for WAVEFORMATEX
w.Write(samplesPerBlock);
w.Write((short)7);//num coefficients
w.Write((short)256); //coeff 0
w.Write((short)0);
w.Write((short)512); //coeff 1
w.Write((short)-256);
w.Write((short)0); //coeff 2
w.Write((short)0);
w.Write((short)192); //coeff 3
w.Write((short)64);
w.Write((short)240); //coeff 4
w.Write((short)0);
w.Write((short)460); //coeff 5
w.Write((short)-208);
w.Write((short)392); //coeff 6
w.Write((short)-232);
w.Write("data".ToCharArray());
w.Write(0); //data size written later...
if (sampleCount != 0)
{
//var sc = sampleCount * sampleSize;
var datalen = Data.Length;
w.Write(Data);
}
else
{
w.Write(Data);
}
ms.Position = 4;
w.Write((int)ms.Length - 8);
ms.Position = 74;// 40;
w.Write((int)ms.Length - 78);// 44);
w.Flush();
ms.Position = 0;
return ms;
}
}
[TC(typeof(EXP))] public class AwcAudioAnimClipDict
{
public byte[] Data { get; set; }
public ClipDictionary ClipDict { get; set; }
public AwcAudioAnimClipDict(DataReader r, AwcChunkInfo info)
{
Data = r.ReadBytes(info.Size);
if ((Data == null) || (Data.Length < 16)) return;
var data = Data;
RpfResourceFileEntry resentry = new RpfResourceFileEntry();
uint rsc7 = BitConverter.ToUInt32(data, 0);
int version = BitConverter.ToInt32(data, 4);
resentry.SystemFlags = BitConverter.ToUInt32(data, 8);
resentry.GraphicsFlags = BitConverter.ToUInt32(data, 12);
if (rsc7 != 0x37435352)
{ } //testing..
if (version != 46) //46 is Clip Dictionary...
{ }
int newlen = data.Length - 16; //trim the header from the data passed to the next step.
int arrlen = Math.Max(newlen, resentry.SystemSize + resentry.GraphicsSize);//expand it as necessary for the reader.
byte[] newdata = new byte[arrlen];
Buffer.BlockCopy(data, 16, newdata, 0, newlen);
data = newdata;
ResourceDataReader rd = new ResourceDataReader(resentry, data);
ClipDict = rd.ReadBlock<ClipDictionary>();
}
public override string ToString()
{
return (ClipDict?.ClipsMapEntries ?? 0).ToString() + " entries";
}
}
[TC(typeof(EXP))] public class AwcAudioUnk
{
public byte[] Data { get; set; }
public AwcAudioUnk(DataReader r, AwcChunkInfo info)
{
Data = r.ReadBytes(info.Size);
}
public override string ToString()
{
if (Data == null) return "";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < Data.Length; i++)
{
if (sb.Length > 0) sb.Append(' ');
sb.Append(Data[i].ToString());
}
return sb.ToString();
}
}
[TC(typeof(EXP))] public class AwcChannelChunkHeader
{
public static uint Size = 16; //24 for ps3...
public uint StartChunk { get; set; }
public uint ChunkCount { get; set; }
public uint SamplesToSkip { get; set; } //mostly 0
public uint SamplesPerChunk { get; set; }
public uint DataSize { get; set; }
public AwcChannelChunkHeader(DataReader r)
{
StartChunk = r.ReadUInt32();
ChunkCount = r.ReadUInt32();
SamplesToSkip = r.ReadUInt32();
SamplesPerChunk = r.ReadUInt32();
DataSize = ChunkCount * 0x800;
//for ps3, two extra ints:
//uint unk0 = r.ReadUint32();
//DataSize = r.ReadUint32();
}
}
[TC(typeof(EXP))] public class AwcChannelChunk
{
public AwcChannelChunkHeader Header { get; set; }
public AwcChannelChunkItemInfo Info { get; set; }
public byte[] Data { get; set; }
public uint TotalDataSize { get; set; }
public AwcChannelChunk(DataReader r, AwcChannelChunkHeader h, AwcChannelChunkItemInfo i)
{
Header = h;
Info = i;
TotalDataSize = h.DataSize;
var rs = i?.RoundSize ?? 0;
int ds = (int)h.DataSize;
if (rs != 0)
{
TotalDataSize = (uint)(TotalDataSize + (((-ds) % rs) + rs) % rs);
}
}
}
}
+491
View File
@@ -0,0 +1,491 @@
using SharpDX;
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 class CacheDatFile : PackedFile
{
public RpfFileEntry FileEntry { get; set; }
public CacheFileDate[] FileDates { get; set; }
public Dictionary<uint, MapDataStoreNode> MapNodeDict { get; set; }
public MapDataStoreNode[] RootMapNodes { get; set; }
//public Dictionary<MetaHash, CInteriorProxy> InteriorProxyDict { get; set; }
public Dictionary<MetaHash, BoundsStoreItem> BoundsStoreDict { get; set; }
public MapDataStoreNode[] AllMapNodes { get; set; }
public CInteriorProxy[] AllCInteriorProxies { get; set; }
public BoundsStoreItem[] AllBoundsStoreItems { get; set; }
public void Load(byte[] data, RpfFileEntry entry)
{
FileEntry = entry;
MemoryStream ms = new MemoryStream(data);
BinaryReader br = new BinaryReader(ms);
StringBuilder sb = new StringBuilder();
for (int i = 0; (i < 100) && (i < data.Length); i++)
{
//read version string.
byte b = data[i];
if (b == 0) break;
sb.Append((char)b);
}
string versionstr = sb.ToString();
sb.Clear();
int lastn = 0;
int lspos = 0;
uint structcount = 0;
uint modlen;
bool indates = false;
List<string> lines = new List<string>();
var dates = new List<CacheFileDate>();
var allMapNodes = new List<MapDataStoreNode>();
var allCInteriorProxies = new List<CInteriorProxy>();
var allBoundsStoreItems = new List<BoundsStoreItem>();
for (int i = 100; i < data.Length; i++)
{
byte b = data[i];
if (b == 0)
break;
if (b == 0xA)
{
lastn = i;
string line = sb.ToString();
lines.Add(line);
switch (line)
{
case "<fileDates>":
indates = true;
break;
case "</fileDates>":
indates = false;
break;
case "<module>":
break;
case "</module>":
break;
case "fwMapDataStore":
ms.Position = i + 1;
modlen = br.ReadUInt32();
structcount = modlen / 64;
lspos = i + (int)modlen + 5;
while (ms.Position<lspos)
{
allMapNodes.Add(new MapDataStoreNode(br));
}
//if (allMapNodes.Count != structcount)
//{ }//test fail due to variable length struct
i += (int)(modlen + 4);
break;
case "CInteriorProxy":
ms.Position = i + 1;
modlen = br.ReadUInt32();
structcount = modlen / 104;
lspos = i + (int)modlen + 5;
while (ms.Position < lspos)
{
allCInteriorProxies.Add(new CInteriorProxy(br));
}
if (allCInteriorProxies.Count != structcount)
{ }//all pass here
i += (int)(modlen + 4);
break;
case "BoundsStore":
ms.Position = i + 1;
modlen = br.ReadUInt32();
structcount = modlen / 32;
lspos = i + (int)modlen + 5;
while (ms.Position < lspos)
{
allBoundsStoreItems.Add(new BoundsStoreItem(br));
}
if (allBoundsStoreItems.Count != structcount)
{ }//all pass here
i += (int)(modlen + 4);
break;
default:
if (!indates)
{ } //just testing
else
{
dates.Add(new CacheFileDate(line));//eg: 2740459947 130680580712018938 8944
}
break;
}
sb.Clear();
}
else
{
sb.Append((char)b);
}
}
FileDates = dates.ToArray();
AllMapNodes = allMapNodes.ToArray();
AllCInteriorProxies = allCInteriorProxies.ToArray();
AllBoundsStoreItems = allBoundsStoreItems.ToArray();
MapNodeDict = new Dictionary<uint, MapDataStoreNode>();
var rootMapNodes = new List<MapDataStoreNode>();
foreach (var mapnode in AllMapNodes)
{
MapNodeDict[mapnode.Name] = mapnode;
if (mapnode.ParentName == 0)
{
rootMapNodes.Add(mapnode);
}
if (mapnode.UnkExtra != null)
{ }//notsure what to do with this
}
foreach (var mapnode in AllMapNodes)
{
MapDataStoreNode pnode;
if (MapNodeDict.TryGetValue(mapnode.ParentName, out pnode))
{
pnode.AddChildToList(mapnode);
}
else if ((mapnode.ParentName != 0))
{ }
}
foreach (var mapnode in AllMapNodes)
{
mapnode.ChildrenListToArray();
}
RootMapNodes = rootMapNodes.ToArray();
BoundsStoreDict = new Dictionary<MetaHash, BoundsStoreItem>();
foreach (BoundsStoreItem item in AllBoundsStoreItems)
{
BoundsStoreItem mbsi = null;
if (BoundsStoreDict.TryGetValue(item.Name, out mbsi))
{ }
BoundsStoreDict[item.Name] = item;
}
//InteriorProxyDict = new Dictionary<MetaHash, CInteriorProxy>();
foreach (CInteriorProxy prx in AllCInteriorProxies)
{
//CInteriorProxy mprx = null;
//if (InteriorProxyDict.TryGetValue(prx.Name, out mprx))
//{ }
//InteriorProxyDict[prx.Name] = prx;//can't do this! multiples with same name different pos
MapDataStoreNode mnode = null;
if (MapNodeDict.TryGetValue(prx.Parent, out mnode))
{
mnode.AddInteriorToList(prx);
}
else
{ }
}
foreach (var mapnode in AllMapNodes)
{
mapnode.InteriorProxyListToArray();
}
br.Dispose();
ms.Dispose();
}
public override string ToString()
{
if (FileEntry != null)
{
return FileEntry.ToString();
}
return base.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class CacheFileDate
{
public MetaHash FileName { get; set; }
public DateTime TimeStamp { get; set; }
public uint FileID { get; set; }
public CacheFileDate(string line)
{
string[] parts = line.Split(' ');
if (parts.Length == 3)
{
FileName = new MetaHash(uint.Parse(parts[0]));
TimeStamp = DateTime.FromFileTimeUtc(long.Parse(parts[1]));
FileID = uint.Parse(parts[2]);
}
else
{ } //testing
}
public override string ToString()
{
return FileName.ToString() + ", " + TimeStamp.ToString() + ", " + FileID.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class BoundsStoreItem
{
public MetaHash Name { get; set; }
public Vector3 Min { get; set; }
public Vector3 Max { get; set; }
public uint Layer { get; set; }
public BoundsStoreItem(Bounds b)
{
Name = 0;
Min = b.BoundingBoxMin;
Max = b.BoundingBoxMax;
Layer = 0;
}
public BoundsStoreItem(BinaryReader br)
{
Name = new MetaHash(br.ReadUInt32());
Min = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
Max = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
Layer = br.ReadUInt32();
}
public override string ToString()
{
return Name.ToString() + ", " +
Min.ToString() + ", " +
Max.ToString() + ", " +
Layer.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class CInteriorProxy
{
public uint Unk01 { get; set; }
public uint Unk02 { get; set; }
public uint Unk03 { get; set; }
public MetaHash Name { get; set; }
public MetaHash Parent { get; set; }
public Vector3 Position { get; set; }
public Quaternion Orientation { get; set; }
public Vector3 BBMin { get; set; }
public Vector3 BBMax { get; set; }
public float Unk11 { get; set; }
public uint Unk12 { get; set; }
public float Unk13 { get; set; }
public uint Unk14 { get; set; }
public float Unk15 { get; set; }
public uint Unk16 { get; set; }
public uint Unk17 { get; set; }
public uint Unk18 { get; set; }
public CInteriorProxy(BinaryReader br)
{
Unk01 = br.ReadUInt32();
Unk02 = br.ReadUInt32();
Unk03 = br.ReadUInt32();
Name = new MetaHash(br.ReadUInt32());
Parent = new MetaHash(br.ReadUInt32());
Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
Orientation = new Quaternion(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
BBMin = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
BBMax = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
Unk11 = br.ReadSingle();
Unk12 = br.ReadUInt32();
Unk13 = br.ReadSingle();
Unk14 = br.ReadUInt32();
Unk15 = br.ReadSingle();
Unk16 = br.ReadUInt32();
Unk17 = br.ReadUInt32();
Unk18 = br.ReadUInt32();
}
public override string ToString()
{
return Unk01.ToString() + ", " +
Unk02.ToString() + ", " +
Unk03.ToString() + ", " +
Name.ToString() + ", " +
Parent.ToString() + ", " +
Position.ToString() + ", " +
Orientation.ToString() + ", " +
BBMin.ToString() + ", " +
BBMax.ToString() + ", " +
Unk11.ToString() + ", " +
Unk12.ToString() + ", " +
Unk13.ToString() + ", " +
Unk14.ToString() + ", " +
Unk15.ToString() + ", " +
Unk16.ToString() + ", " +
Unk17.ToString() + ", " +
Unk18.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class MapDataStoreNode
{
public MetaHash Name { get; set; }
public MetaHash ParentName { get; set; }
public uint ContentFlags { get; set; }
public Vector3 streamingExtentsMin { get; set; }
public Vector3 streamingExtentsMax { get; set; }
public Vector3 entitiesExtentsMin { get; set; }
public Vector3 entitiesExtentsMax { get; set; }
public byte Unk02 { get; set; }
public byte Unk03 { get; set; }
public byte Unk04 { get; set; }
public byte Unk05 { get; set; }
public MapDataStoreNodeExtra UnkExtra { get; set; }
public MapDataStoreNode[] Children { get; set; }
private List<MapDataStoreNode> ChildrenList; //used when building the array
public CInteriorProxy[] InteriorProxies { get; set; }
private List<CInteriorProxy> InteriorProxyList;
public MapDataStoreNode(YmapFile ymap)
{
Name = ymap._CMapData.name;
ParentName = ymap._CMapData.parent;
ContentFlags = ymap._CMapData.contentFlags;
streamingExtentsMin = ymap._CMapData.streamingExtentsMin;
streamingExtentsMax = ymap._CMapData.streamingExtentsMax;
entitiesExtentsMin = ymap._CMapData.entitiesExtentsMin;
entitiesExtentsMax = ymap._CMapData.entitiesExtentsMax;
}
public MapDataStoreNode(BinaryReader br)
{
Name = new MetaHash(br.ReadUInt32());
ParentName = new MetaHash(br.ReadUInt32());
ContentFlags = br.ReadUInt32();
streamingExtentsMin = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
streamingExtentsMax = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
entitiesExtentsMin = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
entitiesExtentsMax = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
Unk02 = br.ReadByte();
Unk03 = br.ReadByte();
Unk04 = br.ReadByte();
Unk05 = br.ReadByte();
if (Unk05 == 0xFE)
{
UnkExtra = new MapDataStoreNodeExtra(br);
}
}
public void AddChildToList(MapDataStoreNode child)
{
if (ChildrenList == null)
{
ChildrenList = new List<MapDataStoreNode>();
}
ChildrenList.Add(child);
}
public void ChildrenListToArray()
{
if (ChildrenList != null)
{
Children = ChildrenList.ToArray();
ChildrenList = null; //plz get this GC
}
}
public void AddInteriorToList(CInteriorProxy iprx)
{
if (InteriorProxyList == null)
{
InteriorProxyList = new List<CInteriorProxy>();
}
InteriorProxyList.Add(iprx);
}
public void InteriorProxyListToArray()
{
if (InteriorProxyList != null)
{
InteriorProxies = InteriorProxyList.ToArray();
InteriorProxyList = null; //plz get this GC
}
}
public override string ToString()
{
return Name.ToString() + ", " +
ParentName.ToString() + ", " +
ContentFlags.ToString() + ", " +
streamingExtentsMin.ToString() + ", " +
streamingExtentsMax.ToString() + ", " +
entitiesExtentsMin.ToString() + ", " +
entitiesExtentsMax.ToString();// + ", " +
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class MapDataStoreNodeExtra
{
public uint Unk01; //0
public byte[] Unk02; //1 - 16 (60 bytes)
public uint Unk03;//16
public uint Unk04;
public uint Unk05;
public uint Unk06;
public uint Unk07;
public uint Unk08;
public uint Unk09;
public uint Unk10;
public string Unk02str
{
get
{
StringBuilder sb = new StringBuilder();
if (Unk02 != null)
{
for (int i = 0; i < Unk02.Length; i++)
{
if (Unk02[i] == 0) break;
sb.Append((char)Unk02[i]);
}
}
return sb.ToString();
}
}
public MapDataStoreNodeExtra(BinaryReader br)
{
Unk01 = br.ReadUInt32();
Unk02 = new byte[60];
for (int i = 0; i < 60; i++)
{
Unk02[i] = br.ReadByte();
}
Unk03 = br.ReadUInt32();
Unk04 = br.ReadUInt32();
Unk05 = br.ReadUInt32();
Unk06 = br.ReadUInt32();
Unk07 = br.ReadUInt32();
Unk08 = br.ReadUInt32();
Unk09 = br.ReadUInt32();
Unk10 = br.ReadUInt32();
}
public override string ToString()
{
return Unk01.ToString() + ", " + Unk02str;
}
}
}
+48
View File
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class CutFile : PackedFile
{
public RpfFileEntry FileEntry { get; set; }
public PsoFile Pso { get; set; }
public void Load(byte[] data, RpfFileEntry entry)
{
//MemoryStream ms = new MemoryStream(data);
FileEntry = entry;
MemoryStream ms = new MemoryStream(data);
if (PsoFile.IsPSO(ms))
{
Pso = new PsoFile();
Pso.Load(ms);
//PsoTypes.EnsurePsoTypes(Pso);
var root = PsoTypes.GetRootEntry(Pso);
if (root != null)
{
}
return;
}
else
{
}
}
}
}
+431
View File
@@ -0,0 +1,431 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker.GameFiles
{
public class DlcContentFile
{
public List<DlcContentDataFile> dataFiles { get; set; } = new List<DlcContentDataFile>();
public List<DlcContentChangeSet> contentChangeSets { get; set; } = new List<DlcContentChangeSet>();
public RpfFile DlcFile { get; set; } //used by GameFileCache
public Dictionary<string, DlcExtraFolderMountFile> ExtraMounts { get; set; } = new Dictionary<string, DlcExtraFolderMountFile>();
public Dictionary<string, DlcContentDataFile> RpfDataFiles { get; set; } = new Dictionary<string, DlcContentDataFile>();
public DlcExtraTitleUpdateFile ExtraTitleUpdates { get; set; }
public void Load(XmlDocument doc)
{
var root = doc.DocumentElement;
dataFiles.Clear();
contentChangeSets.Clear();
foreach (XmlNode node in root.ChildNodes)
{
switch (node.Name)
{
case "disabledFiles":
foreach (XmlNode disabledFile in node.ChildNodes)
{ } //nothing to see here..
break;
case "includedXmlFiles":
foreach (XmlNode includedXmlFile in node.ChildNodes)
{ } //nothing to see here..
break;
case "includedDataFiles":
foreach (XmlNode includedDataFile in node.ChildNodes)
{ } //nothing to see here..
break;
case "dataFiles":
foreach (XmlNode dataFile in node.ChildNodes)
{
if (dataFile.NodeType == XmlNodeType.Element)
{
dataFiles.Add(new DlcContentDataFile(dataFile));
}
}
break;
case "contentChangeSets":
foreach (XmlNode contentChangeSet in node.ChildNodes)
{
if (contentChangeSet.NodeType == XmlNodeType.Element)
{
contentChangeSets.Add(new DlcContentChangeSet(contentChangeSet));
}
}
break;
case "patchFiles":
foreach (XmlNode patchFile in node.ChildNodes)
{ } //nothing to see here..
break;
default:
break;
}
}
}
public void LoadDicts(DlcSetupFile setupfile, RpfManager rpfman, GameFileCache gfc)
{
ExtraMounts.Clear();
RpfDataFiles.Clear();
foreach (var datafile in dataFiles)
{
string dfn = GameFileCache.GetDlcPlatformPath(datafile.filename).ToLower();
if (datafile.fileType == "EXTRA_FOLDER_MOUNT_DATA")
{
string efmdxmlpath = datafile.filename.Replace(setupfile.deviceName + ":", DlcFile.Path).Replace('/', '\\');
efmdxmlpath = gfc.GetDlcPatchedPath(efmdxmlpath);
XmlDocument efmdxml = rpfman.GetFileXml(efmdxmlpath);
DlcExtraFolderMountFile efmf = new DlcExtraFolderMountFile();
efmf.Load(efmdxml);
ExtraMounts[dfn] = efmf;
}
if (datafile.fileType == "EXTRA_TITLE_UPDATE_DATA")
{
string etudxmlpath = datafile.filename.Replace(setupfile.deviceName + ":", DlcFile.Path).Replace('/', '\\');
etudxmlpath = gfc.GetDlcPatchedPath(etudxmlpath);
XmlDocument etudxml = rpfman.GetFileXml(etudxmlpath);
DlcExtraTitleUpdateFile etuf = new DlcExtraTitleUpdateFile();
etuf.Load(etudxml);
ExtraTitleUpdates = etuf;
}
if (datafile.fileType == "RPF_FILE")
{
RpfDataFiles[dfn] = datafile;
}
}
}
public override string ToString()
{
return dataFiles.Count.ToString() + " dataFiles, " + contentChangeSets.Count.ToString() + " contentChangeSets";
}
}
public class DlcContentDataFile
{
public string filename { get; set; }
public string fileType { get; set; }
public string contents { get; set; }
public string installPartition { get; set; }
public bool overlay { get; set; }
public bool disabled { get; set; }
public bool persistent { get; set; }
public bool loadCompletely { get; set; }
public bool locked { get; set; }
public DlcContentDataFile(XmlNode node)
{
Load(node);
}
public void Load(XmlNode node)
{
foreach (XmlNode child in node.ChildNodes)
{
switch (child.Name)
{
case "filename":
filename = child.InnerText;
break;
case "fileType":
fileType = child.InnerText;
break;
case "contents":
contents = child.InnerText;
break;
case "installPartition":
installPartition = child.InnerText;
break;
case "overlay":
overlay = Xml.GetBoolAttribute(child, "value");
break;
case "disabled":
disabled = Xml.GetBoolAttribute(child, "value");
break;
case "persistent":
persistent = Xml.GetBoolAttribute(child, "value");
break;
case "loadCompletely":
loadCompletely = Xml.GetBoolAttribute(child, "value");
break;
case "locked":
locked = Xml.GetBoolAttribute(child, "value");
break;
default:
break;
}
}
}
public override string ToString()
{
return filename + ": " + fileType + ": " + contents + ": " + installPartition +
(overlay ? ", overlay" : "") +
(disabled ? ", disabled" : "") +
(persistent ? ", persistent" : "") +
(loadCompletely ? ", loadCompletely" : "") +
(locked ? ", locked" : "");
}
}
public class DlcContentChangeSet
{
public string changeSetName { get; set; }
public List<string> filesToInvalidate { get; set; }
public List<string> filesToDisable { get; set; }
public List<string> filesToEnable { get; set; }
public List<string> txdToLoad { get; set; }
public List<string> txdToUnload { get; set; }
public List<string> residentResources { get; set; }
public List<string> unregisterResources { get; set; }
public List<DlcContentChangeSet> mapChangeSetData { get; set; }
public string associatedMap { get; set; }
public bool requiresLoadingScreen { get; set; }
public string loadingScreenContext { get; set; }
public bool useCacheLoader { get; set; }
public DlcContentChangeSetExecutionConditions executionConditions { get; set; }
public DlcContentChangeSet(XmlNode node)
{
Load(node);
}
public void Load(XmlNode node)
{
foreach (XmlNode child in node.ChildNodes)
{
switch (child.Name)
{
case "changeSetName":
changeSetName = child.InnerText;
break;
case "filesToInvalidate":
filesToInvalidate = GetChildStringArray(child);
if (filesToInvalidate != null)
{ }
break;
case "filesToDisable":
filesToDisable = GetChildStringArray(child);
if (filesToDisable != null)
{ }
break;
case "filesToEnable":
filesToEnable = GetChildStringArray(child);
if (filesToEnable != null)
{ }
break;
case "txdToLoad":
txdToLoad = GetChildStringArray(child);
if (txdToLoad != null)
{ }
break;
case "txdToUnload":
txdToUnload = GetChildStringArray(child);
if (txdToUnload != null)
{ }
break;
case "residentResources":
residentResources = GetChildStringArray(child);
if (residentResources != null)
{ }
break;
case "unregisterResources":
unregisterResources = GetChildStringArray(child);
if (unregisterResources != null)
{ }
break;
case "mapChangeSetData":
mapChangeSetData = new List<DlcContentChangeSet>();
foreach (XmlNode mapChangeSetDataItem in child.ChildNodes)
{
mapChangeSetData.Add(new DlcContentChangeSet(mapChangeSetDataItem));
}
break;
case "associatedMap":
associatedMap = child.InnerText;
break;
case "requiresLoadingScreen":
requiresLoadingScreen = Xml.GetBoolAttribute(child, "value");
break;
case "loadingScreenContext":
loadingScreenContext = child.InnerText;
break;
case "useCacheLoader":
useCacheLoader = Xml.GetBoolAttribute(child, "value");
break;
case "executionConditions":
executionConditions = new DlcContentChangeSetExecutionConditions(child);
break;
default:
break;
}
}
}
private List<string> GetChildStringArray(XmlNode node)
{
if (!node.HasChildNodes) return null;
var result = new List<string>();
foreach (XmlNode child in node.ChildNodes)
{
if (child.NodeType == XmlNodeType.Element)
{
result.Add(child.InnerText);
}
}
return result;
}
public override string ToString()
{
return (changeSetName != null) ? changeSetName : (associatedMap != null) ? associatedMap : null;
}
}
public class DlcContentChangeSetExecutionConditions
{
public string activeChangesetConditions { get; set; }
public string genericConditions { get; set; }
public DlcContentChangeSetExecutionConditions(XmlNode node)
{
Load(node);
}
public void Load(XmlNode node)
{
foreach (XmlNode child in node.ChildNodes)
{
if (child.NodeType != XmlNodeType.Element) continue;
switch (child.Name)
{
case "activeChangesetConditions":
activeChangesetConditions = child.InnerText;
break;
case "genericConditions":
genericConditions = child.InnerText;
break;
default:
break;
}
}
}
public override string ToString()
{
return (string.IsNullOrEmpty(activeChangesetConditions) ? "" : activeChangesetConditions + ", ") + (string.IsNullOrEmpty(genericConditions) ? "" : genericConditions);
}
}
public class DlcExtraFolderMountFile
{
public List<DlcExtraFolderMount> FolderMounts { get; set; } = new List<DlcExtraFolderMount>();
public void Load(XmlDocument doc)
{
var root = doc.DocumentElement;
XmlNodeList mountitems = doc.SelectNodes("SExtraFolderMountData/FolderMounts/Item");
FolderMounts.Clear();
for (int i = 0; i < mountitems.Count; i++)
{
var mount = new DlcExtraFolderMount();
mount.Init(mountitems[i]);
FolderMounts.Add(mount);
}
}
public override string ToString()
{
return "(" + FolderMounts.Count.ToString() + " FolderMounts)";
}
}
public class DlcExtraFolderMount
{
public string type { get; set; }
public string platform { get; set; }
public string path { get; set; }
public string mountAs { get; set; }
public void Init(XmlNode node)
{
type = Xml.GetStringAttribute(node, "type");
platform = Xml.GetStringAttribute(node, "platform");
path = Xml.GetChildInnerText(node, "path");
mountAs = Xml.GetChildInnerText(node, "mountAs");
}
public override string ToString()
{
return type + ": " + path + " - " + mountAs + ((platform != null) ? (" (" + platform + ")") : "");
}
}
public class DlcExtraTitleUpdateFile
{
public List<DlcExtraTitleUpdateMount> Mounts { get; set; } = new List<DlcExtraTitleUpdateMount>();
public void Load(XmlDocument doc)
{
var root = doc.DocumentElement;
XmlNodeList mountitems = doc.SelectNodes("SExtraTitleUpdateData/Mounts/Item");
Mounts.Clear();
for (int i = 0; i < mountitems.Count; i++)
{
var mount = new DlcExtraTitleUpdateMount();
mount.Init(mountitems[i]);
Mounts.Add(mount);
}
}
public override string ToString()
{
return "(" + Mounts.Count.ToString() + " Mounts)";
}
}
public class DlcExtraTitleUpdateMount
{
public string type { get; set; }
public string deviceName { get; set; }
public string path { get; set; }
public void Init(XmlNode node)
{
type = Xml.GetStringAttribute(node, "type");
deviceName = Xml.GetChildInnerText(node, "deviceName");
path = Xml.GetChildInnerText(node, "path");
}
public override string ToString()
{
return type + ": " + deviceName + " - " + path;
}
}
}
+82
View File
@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker.GameFiles
{
public class DlcSetupFile
{
public string deviceName { get; set; }
public string datFile { get; set; }
public string nameHash { get; set; }
public List<DlcSetupContentChangesetGroup> contentChangeSetGroups { get; set; }
public string type { get; set; }
public string timeStamp { get; set; }
public int order { get; set; }
public int minorOrder { get; set; }
public int subPackCount { get; set; }
public bool isLevelPack { get; set; }
public RpfFile DlcFile { get; set; } //used by GameFileCache
public DlcContentFile ContentFile { get; set; }
public void Load(XmlDocument doc)
{
var root = doc.DocumentElement;
deviceName = Xml.GetChildInnerText(root, "deviceName");
datFile = Xml.GetChildInnerText(root, "datFile");
nameHash = Xml.GetChildInnerText(root, "nameHash");
type = Xml.GetChildInnerText(root, "type");
timeStamp = Xml.GetChildInnerText(root, "timeStamp");
order = Xml.GetIntAttribute(root.SelectSingleNode("order"), "value");
minorOrder = Xml.GetIntAttribute(root.SelectSingleNode("minorOrder"), "value");
subPackCount = Xml.GetIntAttribute(root.SelectSingleNode("subPackCount"), "value");
isLevelPack = Xml.GetBoolAttribute(root.SelectSingleNode("isLevelPack"), "value");
contentChangeSetGroups = new List<DlcSetupContentChangesetGroup>();
var groups = root.SelectNodes("contentChangeSetGroups/Item");
foreach (XmlNode node in groups)
{
var group = new DlcSetupContentChangesetGroup();
group.Load(node);
contentChangeSetGroups.Add(group);
}
if (root.ChildNodes.Count > 15)
{ }
}
public override string ToString()
{
return deviceName + ", " + datFile + ", " + nameHash + ", " + type + ", " + order.ToString() + ", " + ((contentChangeSetGroups != null) ? contentChangeSetGroups.Count.ToString() : "0") + " groups, " + timeStamp;
}
}
public class DlcSetupContentChangesetGroup
{
public string NameHash { get; set; }
public List<string> ContentChangeSets { get; set; }
public void Load(XmlNode node)
{
if (node.ChildNodes.Count != 2)
{ }
NameHash = Xml.GetChildInnerText(node, "NameHash");
ContentChangeSets = new List<string>();
var changesets = node.SelectNodes("ContentChangeSets/Item");
foreach (XmlNode changeset in changesets)
{
ContentChangeSets.Add(changeset.InnerText);
}
}
public override string ToString()
{
return NameHash + " (" + ((ContentChangeSets != null) ? ContentChangeSets.Count.ToString() : "0") + " changesets)";
}
}
}
File diff suppressed because it is too large Load Diff
+164
View File
@@ -0,0 +1,164 @@
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 Gxt2File : PackedFile
{
public string Name { get; set; }
public RpfFileEntry FileEntry { get; set; }
public uint EntryCount { get; set; }
public Gxt2Entry[] TextEntries { get; set; }
//public Dictionary<uint, string> Dict { get; set; }
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
FileEntry = entry;
//Dict = new Dictionary<uint, string>();
using (BinaryReader br = new BinaryReader(new MemoryStream(data)))
{
uint gxt2 = br.ReadUInt32(); //"GXT2" - 1196971058
if (gxt2 != 1196971058)
{ return; }
EntryCount = br.ReadUInt32();
TextEntries = new Gxt2Entry[EntryCount];
for (uint i = 0; i < EntryCount; i++)
{
var e = new Gxt2Entry();
e.Hash = br.ReadUInt32();
e.Offset = br.ReadUInt32();
TextEntries[i] = e;
}
gxt2 = br.ReadUInt32(); //another "GXT2"
if (gxt2 != 1196971058)
{ return; }
uint endpos = br.ReadUInt32();
List<byte> buf = new List<byte>();
for (uint i = 0; i < EntryCount; i++)
{
var e = TextEntries[i];
br.BaseStream.Position = e.Offset;
buf.Clear();
byte b = br.ReadByte();
while ((b != 0) && (br.BaseStream.Position<endpos))
{
buf.Add(b);
b = br.ReadByte();
}
e.Text = Encoding.UTF8.GetString(buf.ToArray());
//Dict[e.Hash] = e.Text;
}
}
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class Gxt2Entry
{
public uint Hash { get; set; }
public uint Offset { get; set; }
public string Text { get; set; }
public override string ToString()
{
return Convert.ToString(Hash, 16).ToUpper().PadLeft(8, '0') + ": " + Text;
}
}
public static class GlobalText
{
public static Dictionary<uint, string> Index = new Dictionary<uint, string>();
private static object syncRoot = new object();
public static volatile bool FullIndexBuilt = false;
public static void Clear()
{
lock (syncRoot)
{
Index.Clear();
}
}
public static bool Ensure(string str)
{
uint hash = JenkHash.GenHash(str);
if (hash == 0) return true;
lock (syncRoot)
{
if (!Index.ContainsKey(hash))
{
Index.Add(hash, str);
return false;
}
}
return true;
}
public static bool Ensure(string str, uint hash)
{
if (hash == 0) return true;
lock (syncRoot)
{
if (!Index.ContainsKey(hash))
{
Index.Add(hash, str);
return false;
}
}
return true;
}
public static string GetString(uint hash)
{
string res;
lock (syncRoot)
{
if (!Index.TryGetValue(hash, out res))
{
res = hash.ToString();
}
}
return res;
}
public static string TryGetString(uint hash)
{
string res;
lock (syncRoot)
{
if (!Index.TryGetValue(hash, out res))
{
res = string.Empty;
}
}
return res;
}
}
}
+48
View File
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class JPsoFile : PackedFile
{
public RpfFileEntry FileEntry { get; set; }
public PsoFile Pso { get; set; }
public void Load(byte[] data, RpfFileEntry entry)
{
//MemoryStream ms = new MemoryStream(data);
FileEntry = entry;
MemoryStream ms = new MemoryStream(data);
if (PsoFile.IsPSO(ms))
{
Pso = new PsoFile();
Pso.Load(ms);
//PsoTypes.EnsurePsoTypes(Pso);
var root = PsoTypes.GetRootEntry(Pso);
if (root != null)
{
}
return;
}
else
{
}
}
}
}
+800
View File
@@ -0,0 +1,800 @@
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 RelFile : PackedFile
{
public RpfFileEntry FileEntry { get; set; }
public string Name { get; set; }
public uint Type { get; set; }
public uint DataLength { get; set; }
public byte[] DataBlock { get; set; }
public uint DataUnkVal { get; set; }
public uint NameTableLength { get; set; }
public uint NameTableCount { get; set; }
public uint[] NameTableOffsets { get; set; }
public string[] NameTable { get; set; }
public uint IndexCount { get; set; }
public uint IndexStringFlags { get; set; }
public RelIndexHash[] IndexHashes { get; set; }
public RelIndexString[] IndexStrings { get; set; }
public uint Unk05Count { get; set; }
public uint[] Unk05Arr { get; set; }
public MetaHash[] Unk05Hashes { get; set; }
public uint Unk06Count { get; set; }
public uint[] Unk06Arr { get; set; }
public MetaHash[] Unk06Hashes { get; set; }
public RelData[] RelDatas { get; set; }
public RelData[] RelDatasSorted { get; set; }
//testing zone for decoding .rel audio files.
public RelFile()
{
}
public RelFile(RpfFileEntry entry)
{
FileEntry = entry;
}
public void Load(byte[] data, RpfFileEntry entry)
{
FileEntry = entry;
Name = entry.Name;
MemoryStream ms = new MemoryStream(data);
BinaryReader br = new BinaryReader(ms);
StringBuilder sb = new StringBuilder();
Type = br.ReadUInt32(); //type/version?
DataLength = br.ReadUInt32(); //length of data block
DataBlock = br.ReadBytes((int)DataLength); //data block... synth infos? script?
NameTableLength = br.ReadUInt32(); //length of this nametable block
NameTableCount = br.ReadUInt32();
if (NameTableCount > 0)
{
uint[] d02 = new uint[NameTableCount]; //string offsets
for (uint i = 0; i < NameTableCount; i++)
{
d02[i] = br.ReadUInt32();
}
NameTableOffsets = d02;
string[] names = new string[NameTableCount];
for (uint i = 0; i < NameTableCount; i++)
{
sb.Clear();
while (true)
{
char c = (char)br.ReadByte();
if (c != 0) sb.Append(c);
else break;
}
names[i] = sb.ToString();
}
NameTable = names;
}
IndexCount = br.ReadUInt32(); //count of index items
if (IndexCount > 0)
{
//checking NameTableLength here doesn't make sense!
if ((Type == 4) && (NameTableLength == 4))//audioconfig.dat4.rel
{
IndexStringFlags = br.ReadUInt32(); //what is this? 2524
RelIndexString[] indexstrs = new RelIndexString[IndexCount];
for (uint i = 0; i < IndexCount; i++)
{
byte sl = br.ReadByte();
sb.Clear();
for (int j = 0; j < sl; j++)
{
char c = (char)br.ReadByte();
if (c != 0) sb.Append(c);
}
RelIndexString cunk01 = new RelIndexString();
cunk01.Name = sb.ToString();
cunk01.Offset = br.ReadUInt32();
cunk01.Length = br.ReadUInt32();
indexstrs[i] = cunk01;
}
IndexStrings = indexstrs;
}
else //for all other .rel files...
{
RelIndexHash[] indexhashes = new RelIndexHash[IndexCount];
for (uint i = 0; i < IndexCount; i++)
{
RelIndexHash unk01 = new RelIndexHash();
unk01.Name = new MetaHash(br.ReadUInt32());
unk01.Offset = br.ReadUInt32();
unk01.Length = br.ReadUInt32();
indexhashes[i] = unk01;
}
IndexHashes = indexhashes;
}
}
Unk05Count = br.ReadUInt32();
if (Unk05Count != 0)
{
uint[] d05 = new uint[Unk05Count];
MetaHash[] d05h = new MetaHash[Unk05Count];
for (uint i = 0; i < Unk05Count; i++)
{
d05[i] = br.ReadUInt32();
var pos = ms.Position;
ms.Position = d05[i];
d05h[i] = new MetaHash(br.ReadUInt32());
ms.Position = pos;
}
Unk05Arr = d05;
Unk05Hashes = d05h;
}
Unk06Count = br.ReadUInt32();
if (Unk06Count != 0)
{
uint[] d06 = new uint[Unk06Count];
MetaHash[] d06h = new MetaHash[Unk06Count];
for (uint i = 0; i < Unk06Count; i++)
{
d06[i] = br.ReadUInt32();
var pos = ms.Position;
ms.Position = d06[i];
d06h[i] = new MetaHash(br.ReadUInt32());
ms.Position = pos;
}
Unk06Arr = d06;
Unk06Hashes = d06h;
}
if (ms.Position != ms.Length)
{ }
//EOF!
br.Dispose();
ms.Dispose();
ParseDataBlock();
}
private void ParseDataBlock()
{
MemoryStream ms = new MemoryStream(DataBlock);
BinaryReader br = new BinaryReader(ms);
DataUnkVal = br.ReadUInt32(); //3 bytes used... for? ..version?
switch (DataUnkVal)
{
case 5252715: //dlcbusiness_amp.dat10.rel
case 5301323: //dlcbeach_game.dat149.rel
case 5378673: //dlcmpheist_game.dat150.rel
case 5750395: //dlcbeach_game.dat150.rel
case 6353778: //dlcbeach_game.dat151.rel
case 6894089: //dlcpilotschool_game.dat151.rel
case 6978435: //dlcxmas2_amp.dat10.rel
case 7126027: //audioconfig.dat4.rel
case 7314721: //dlcmpheist_amp.dat10.rel
case 7516460: //dlcpd03_game.dat151.rel
case 7917027: //dlcluxe_amp.dat10.rel
case 7921508: //dlcluxe_game.dat151.rel
case 8149475: //dlcluxe2_amp.dat10.rel
case 8751734: //dlcsfx1_game.dat151.rel
case 9028036: //dlchalloween_amp.dat10.rel
case 9037528: //dlclowrider_amp.dat10.rel
case 9458585: //dlcapartment_amp.dat10.rel
case 9486222: //dlcapartment_mix.dat15.rel
case 9806108: //mpvalentines2_amp.dat10.rel
case 9813679: //dlcjanuary2016_amp.dat10.rel
case 10269543://dlclow2_amp.dat10.rel
case 10891463://dlcexec1_amp.dat10.rel
case 11171338://dlcstunt_amp.dat10.rel
case 11918985://dlcbiker_amp.dat10.rel
case 12470522://dlcimportexport_amp.dat10.rel
case 12974726://audioconfig.dat4.rel
case 13117164://dlcspecialraces_amp.dat10.rel
break;
default:
break;
}
List<RelData> reldatas = new List<RelData>();
if (IndexHashes != null)
{
foreach (var indexhash in IndexHashes)
{
ms.Position = indexhash.Offset;
RelData d = new RelData();
d.NameHash = indexhash.Name;
d.Offset = indexhash.Offset;
d.Length = indexhash.Length;
d.Data = br.ReadBytes((int)indexhash.Length);
reldatas.Add(d);
}
}
else if (IndexStrings != null)
{
foreach (var indexstr in IndexStrings)
{
ms.Position = indexstr.Offset;
RelData d = new RelData();
d.Name = indexstr.Name;
d.Offset = indexstr.Offset;
d.Length = indexstr.Length;
d.Data = br.ReadBytes((int)indexstr.Length);
reldatas.Add(d);
}
}
RelDatas = reldatas.ToArray();
reldatas.Sort((d1, d2) => d1.Offset.CompareTo(d2.Offset));
RelDatasSorted = reldatas.ToArray();
br.Dispose();
ms.Dispose();
foreach (var d in RelDatas)
{
using (BinaryReader dbr = new BinaryReader(new MemoryStream(d.Data)))
{
switch (Type)
{
case 4: //00000100 //speech.dat4.rel, audioconfig.dat4.rel
ParseData4(d, dbr);
break;
case 10: //00001010 //amp.dat10.rel
ParseData10(d, dbr);
break;
case 15: //00001111 //mix.dat15.rel
ParseData15(d, dbr);
break;
case 16: //00010000 //curves.dat16.rel
ParseData16(d, dbr);
break;
case 22: //00010110 //categories.dat22.rel
ParseData22(d, dbr);
break;
case 54: //00110110 //sounds.dat54.rel
ParseData54(d, dbr);
break;
case 149: //10010101 //game.dat149.rel
ParseData149(d, dbr);
break;
case 150: //10010110 //game.dat150.rel
ParseData150(d, dbr);
break;
case 151: //10010111 //game.dat151.rel
ParseData151(d, dbr);
break;
default:
break;
}
}
}
}
private void ParseData4(RelData d, BinaryReader br)
{
//speech.dat4.rel, audioconfig.dat4.rel
if (d.Length == 1)
{
byte b = br.ReadByte();
switch (b)
{
case 0:
case 25:
case 28:
case 34:
case 89:
case 94:
case 178:
break;
default:
break;
}
return;
}
if (d.Length == 2)
{
byte b = br.ReadByte();
switch (b)
{
case 4:
case 1:
case 15:
case 12:
case 3:
case 2:
case 7:
case 5:
case 158:
case 25:
case 16:
case 64:
case 6:
case 8:
case 14:
case 22:
case 18:
case 20:
case 32:
case 17:
case 30:
case 9:
case 0:
case 47:
case 224:
case 200:
case 136:
case 45:
case 54:
case 28:
case 19:
case 37:
case 61:
case 38:
case 128:
case 24:
case 26:
case 40:
case 13:
case 36:
case 78:
case 34:
case 10:
case 21:
case 192:
case 60:
case 29:
case 33:
case 72:
case 57:
case 133:
case 11:
break;
default:
break;
}
return;
}
if (d.Length == 4)
{
uint h = br.ReadUInt32();
return;
}
byte b00 = br.ReadByte();
switch (b00)
{
case 4:
case 1:
case 0:
case 6:
case 3:
case 2:
case 5:
case 7:
case 15:
case 10:
case 8:
case 9:
break;
case 23:
case 12:
case 11:
case 16:
case 13:
case 36:
case 30:
case 31:
case 27:
case 20:
case 19:
case 14:
case 40:
case 46:
case 22:
case 18:
case 21:
case 45:
case 17:
case 48:
case 87:
case 38:
case 28:
case 29:
case 43:
case 69:
case 50:
case 25:
case 32:
case 35:
case 34:
break;
default:
break;
}
}
private void ParseData10(RelData d, BinaryReader br)
{
//amp.dat10.rel
byte b00 = br.ReadByte();
switch (b00)
{
case 1:
case 3:
break;
default:
break;
}
}
private void ParseData15(RelData d, BinaryReader br)
{
//mix.dat15.rel
byte b00 = br.ReadByte();
switch (b00)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
break;
default:
break;
}
}
private void ParseData16(RelData d, BinaryReader br)
{
//curves.dat16.rel
byte b00 = br.ReadByte();
switch (b00)
{
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 12:
case 13:
case 15:
break;
default:
break;
}
}
private void ParseData22(RelData d, BinaryReader br)
{
//categories.dat22.rel
byte b00 = br.ReadByte();
switch (b00)
{
case 0:
break;
default:
break;
}
}
private void ParseData54(RelData d, BinaryReader br)
{
//sounds.dat54.rel
byte b00 = br.ReadByte();
switch (b00)
{
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25:
case 26:
case 27:
case 28:
case 29:
case 30:
case 31:
case 32:
case 33:
case 34:
case 35:
break;
default:
break;
}
}
private void ParseData149(RelData d, BinaryReader br)
{
//game.dat149.rel
byte b00 = br.ReadByte();
switch (b00)
{
case 3:
case 4:
case 17:
case 50:
case 57:
case 62:
case 63:
case 66:
case 76:
case 88:
case 90:
break;
default:
break;
}
}
private void ParseData150(RelData d, BinaryReader br)
{
//game.dat150.rel
byte b00 = br.ReadByte();
switch (b00)
{
case 3:
case 4:
case 6:
case 8:
case 17:
case 32:
case 37:
case 38:
case 39:
case 47:
case 50:
case 52:
case 57:
case 62:
case 63:
case 64:
case 65:
case 66:
case 76:
case 88:
case 90:
case 117:
break;
default:
break;
}
}
private void ParseData151(RelData d, BinaryReader br)
{
//game.dat151.rel
byte b00 = br.ReadByte(); //???
switch (b00)
{
case 1://new
case 2://new
case 3:
case 4:
case 5://new
case 6:
case 7://new
case 8://
case 9://new
case 11://new
case 12://new
case 13://new
case 14://new
case 15://new
case 16://new
case 17:
case 18://new
case 22://new
case 23://new
case 24://new
case 25://new
case 26://new
case 27://new
case 28://new
case 29://new
case 30://new
case 31://new
case 32://
case 33://new
case 35://new
case 36://new
case 37://
case 38://
case 39://
case 40://new
case 41://new
case 42://new
case 44://new
case 45://new
case 46://new
case 47://
case 48://new
case 49://new
case 50:
case 51://new
case 52://
case 53://new
case 54://new
case 55://new
case 56://new
case 57:
case 59://new
case 62:
case 63:
case 64:
case 65://
case 66:
case 67://new
case 68://new
case 69://new
case 70://new
case 71://new
case 72://new
case 73://new
case 74://new
case 75://new
case 76:
case 77://new
case 78://new
case 79://new
case 80://new
case 81://new
case 82://new
case 83://new
case 84://new
case 85://new
case 86://new
case 87://new
case 88:
case 90:
case 91://new
case 92://new
case 93://new
case 94://new
case 95://new
case 96://new
case 98://new
case 99://new
case 100://new
case 101://new
case 102://new
case 103://new
case 104://new
case 105://new
case 106://new
case 107://new
case 108://new
case 109://new
case 110://new
case 111://new
case 112://new
case 113://new
case 114://new
case 115://new
case 116://new
case 117:
case 118://new
case 119://new
case 120://new
case 121://new
break;
default:
break;
}
}
public override string ToString()
{
return Name;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))]
public struct RelIndexHash
{
public MetaHash Name { get; set; }
public uint Offset { get; set; }
public uint Length { get; set; }
public override string ToString()
{
return Name.ToString() + ", " + Offset.ToString() + ", " + Length.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))]
public struct RelIndexString
{
public string Name { get; set; }
public uint Offset { get; set; }
public uint Length { get; set; }
public override string ToString()
{
return Name + ", " + Offset.ToString() + ", " + Length.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))]
public class RelData
{
public MetaHash NameHash { get; set; }
public string Name { get; set; }
public uint Offset { get; set; }
public uint Length { get; set; }
public byte[] Data { get; set; }
public override string ToString()
{
string ol= ", " + Offset.ToString() + ", " + Length.ToString();
if (!string.IsNullOrEmpty(Name)) return Name + ol;
return NameHash.ToString() + ol;
}
}
}
+84
View File
@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public static class StatsNames
{
public static Dictionary<uint, string> Index = new Dictionary<uint, string>();
private static object syncRoot = new object();
public static volatile bool FullIndexBuilt = false;
public static void Clear()
{
lock (syncRoot)
{
Index.Clear();
}
}
public static bool Ensure(string str)
{
uint hash = JenkHash.GenHash(str);
if (hash == 0) return true;
lock (syncRoot)
{
if (!Index.ContainsKey(hash))
{
Index.Add(hash, str);
return false;
}
}
return true;
}
public static bool Ensure(string str, uint hash)
{
if (hash == 0) return true;
lock (syncRoot)
{
if (!Index.ContainsKey(hash))
{
Index.Add(hash, str);
return false;
}
}
return true;
}
public static string GetString(uint hash)
{
string res;
lock (syncRoot)
{
if (!Index.TryGetValue(hash, out res))
{
res = hash.ToString();
}
}
return res;
}
public static string TryGetString(uint hash)
{
string res;
lock (syncRoot)
{
if (!Index.TryGetValue(hash, out res))
{
res = string.Empty;
}
}
return res;
}
}
}
+44
View File
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YbnFile : GameFile, PackedFile
{
public Bounds Bounds { get; set; }
public YbnFile() : base(null, GameFileType.Ybn)
{
}
public YbnFile(RpfFileEntry entry) : base(entry, GameFileType.Ybn)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
Bounds = rd.ReadBlock<Bounds>();
Bounds.OwnerName = entry.Name;
Loaded = true;
}
}
}
+55
View File
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YcdFile : GameFile, PackedFile
{
public ClipDictionary ClipDictionary { get; set; }
public Dictionary<MetaHash, ClipMapEntry> ClipMap { get; set; }
public YcdFile() : base(null, GameFileType.Ycd)
{
}
public YcdFile(RpfFileEntry entry) : base(entry, GameFileType.Ycd)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
//Name = entry.Name;
//Hash = entry.ShortNameHash;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
ClipDictionary = rd.ReadBlock<ClipDictionary>();
ClipMap = new Dictionary<MetaHash, ClipMapEntry>();
if ((ClipDictionary != null) && (ClipDictionary.Clips != null) && (ClipDictionary.Clips.data_items != null))
{
foreach (var cme in ClipDictionary.Clips.data_items)
{
if (cme != null)
{
ClipMap[cme.Hash] = cme;
}
}
}
}
}
}
+89
View File
@@ -0,0 +1,89 @@
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 YddFile : GameFile, PackedFile
{
//public DrawableDictionary DrawableDict { get; set; }
public Dictionary<uint, Drawable> Dict { get; set; }
public Drawable[] Drawables { get; set; }
public YddFile() : base(null, GameFileType.Ydd)
{
}
public YddFile(RpfFileEntry entry) : base(entry, GameFileType.Ydd)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
DrawableDictionary DrawableDict = rd.ReadBlock<DrawableDictionary>();
//MemoryUsage = 0; //uses decompressed filesize now...
//if (DrawableDict != null)
//{
// MemoryUsage += DrawableDict.MemoryUsage;
//}
if ((DrawableDict != null) &&
(DrawableDict.Drawables != null) &&
(DrawableDict.Drawables.data_items != null) &&
(DrawableDict.Hashes != null))
{
Dict = new Dictionary<uint, Drawable>();
var drawables = DrawableDict.Drawables.data_items;
var hashes = DrawableDict.Hashes;
for (int i = 0; (i < drawables.Length) && (i < hashes.Length); i++)
{
var drawable = drawables[i];
var hash = hashes[i];
Dict[hash] = drawable;
drawable.Owner = this;
}
for (int i = 0; (i < drawables.Length) && (i < hashes.Length); i++)
{
var drawable = drawables[i];
var hash = hashes[i];
if ((drawable.Name == null) || (drawable.Name.EndsWith("#dd")))
{
string hstr = JenkIndex.TryGetString(hash);
if (!string.IsNullOrEmpty(hstr))
{
drawable.Name = hstr;
}
else
{ }
}
}
Drawables = Dict.Values.ToArray();
}
Loaded = true;
}
}
}
+59
View File
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YdrFile : GameFile, PackedFile
{
public Drawable Drawable { get; set; }
public YdrFile() : base(null, GameFileType.Ydr)
{
}
public YdrFile(RpfFileEntry entry) : base(entry, GameFileType.Ydr)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
//MemoryUsage = 0;
try
{
Drawable = rd.ReadBlock<Drawable>();
Drawable.Owner = this;
//MemoryUsage += Drawable.MemoryUsage; //uses decompressed filesize now...
}
catch (Exception ex)
{
string err = ex.ToString();
}
Loaded = true;
}
}
}
+50
View File
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YftFile : GameFile, PackedFile
{
public FragType Fragment { get; set; }
public YftFile() : base(null, GameFileType.Yft)
{
}
public YftFile(RpfFileEntry entry) : base(entry, GameFileType.Yft)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
Fragment = rd.ReadBlock<FragType>();
if (Fragment.Drawable != null)
{
Fragment.Drawable.Owner = this;
}
if (Fragment.Unknown_F8h_Data != null)
{
Fragment.Unknown_F8h_Data.Owner = this;
}
Loaded = true;
}
}
}
File diff suppressed because it is too large Load Diff
+187
View File
@@ -0,0 +1,187 @@
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 class YmfFile : PackedFile
{
public RpfFileEntry FileEntry { get; set; }
public Meta Meta { get; set; }
public PsoFile Pso { get; set; }
public RbfFile Rbf { get; set; }
public YmfMapDataGroup[] MapDataGroups { get; set; }
public CImapDependency[] imapDependencies { get; set; }
public YmfImapDependency2[] imapDependencies2 { get; set; }
public YmfItypDependency2[] itypDependencies2 { get; set; }
public CHDTxdAssetBinding[] HDTxdAssetBindings { get; set; }
public YmfInterior[] Interiors { get; set; }
public void Load(byte[] data, RpfFileEntry entry)
{
FileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
MemoryStream ms = new MemoryStream(data);
if (RbfFile.IsRBF(ms))
{
Rbf = new RbfFile();
Rbf.Load(ms);
//x64j.rpf\\levels\\gta5\\_citye\\indust_01\\id1_props.rpf\\_manifest.ymf
//x64j.rpf\\levels\\gta5\\_citye\\indust_02\\id2_props.rpf\\_manifest.ymf
//x64q.rpf\\levels\\gta5\\_hills\\country_01\\cs1_railwyc.rpf\\_manifest.ymf
//all just HDTxd bindings
return;
}
if (PsoFile.IsPSO(ms))
{
Pso = new PsoFile();
Pso.Load(ms);
//PsoTypes.EnsurePsoTypes(Pso);
ProcessPSO();
return;
}
else
{
}
return;
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
Meta = rd.ReadBlock<Meta>();
}
private void ProcessPSO()
{
//See x64m.rpf\levels\gta5\_cityw\venice_01\venice_metadata.rpf\_manifest.ymf
//for TIMED YMAP stuff!!!!
//check CMapDataGroup.HoursOnOff
var d = PsoTypes.GetRootItem<CPackFileMetaData>(Pso);
MapDataGroups = PsoTypes.GetObjectArray<YmfMapDataGroup, CMapDataGroup>(Pso, d.MapDataGroups);
imapDependencies = PsoTypes.GetItemArray<CImapDependency>(Pso, d.imapDependencies);
imapDependencies2 = PsoTypes.GetObjectArray<YmfImapDependency2, CImapDependencies>(Pso, d.imapDependencies_2);
itypDependencies2 = PsoTypes.GetObjectArray<YmfItypDependency2, CItypDependencies>(Pso, d.itypDependencies_2);
HDTxdAssetBindings = PsoTypes.GetItemArray<CHDTxdAssetBinding>(Pso, d.HDTxdBindingArray);
Interiors = PsoTypes.GetObjectArray<YmfInterior, Unk_741495440>(Pso, d.Interiors);
}
public override string ToString()
{
return (FileEntry != null) ? FileEntry.Path : string.Empty;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class YmfMapDataGroup : PsoClass<CMapDataGroup>
{
public CMapDataGroup DataGroup { get; set; } //ymap name
public MetaHash[] Bounds { get; set; }
public MetaHash[] WeatherTypes { get; set; }
public MetaHash Name { get; set; }
public ushort Flags { get; set; }
public uint HoursOnOff { get; set; }
public override string ToString()
{
return DataGroup.ToString();
}
public override void Init(PsoFile pso, ref CMapDataGroup v)
{
DataGroup = v;
Bounds = PsoTypes.GetHashArray(pso, v.Bounds);
WeatherTypes = PsoTypes.GetHashArray(pso, v.WeatherTypes);
Name = v.Name;
Flags = v.Flags;
HoursOnOff = v.HoursOnOff;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class YmfImapDependency2 : PsoClass<CImapDependencies>
{
public CImapDependencies Dep { get; set; }
public MetaHash[] itypDepArray { get; set; }//ybn hashes?
public override void Init(PsoFile pso, ref CImapDependencies v)
{
Dep = v;
itypDepArray = PsoTypes.GetHashArray(pso, v.itypDepArray);
}
public override string ToString()
{
return Dep.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class YmfItypDependency2 : PsoClass<CItypDependencies>
{
public CItypDependencies Dep { get; set; }
public MetaHash[] itypDepArray { get; set; }//ytyp hashes?
public override void Init(PsoFile pso, ref CItypDependencies v)
{
Dep = v;
itypDepArray = PsoTypes.GetHashArray(pso, v.itypDepArray);
}
public override string ToString()
{
return Dep.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class YmfInterior : PsoClass<Unk_741495440>
{
public Unk_741495440 Interior { get; set; }
public MetaHash[] Bounds { get; set; }//ybn hashes?
public override string ToString()
{
return Interior.ToString();
}
public override void Init(PsoFile pso, ref Unk_741495440 v)
{
Interior = v;
Bounds = PsoTypes.GetHashArray(pso, v.Bounds);
}
}
}
+372
View File
@@ -0,0 +1,372 @@
using CodeWalker.World;
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 YmtFile : GameFile, PackedFile
{
public Meta Meta { get; set; }
public PsoFile Pso { get; set; }
public RbfFile Rbf { get; set; }
public YmtFileFormat FileFormat { get; set; } = YmtFileFormat.Unknown;
public YmtFileContentType ContentType { get; set; } = YmtFileContentType.None;
public Dictionary<string,string> CMapParentTxds { get; set; }
public YmtScenarioPointManifest CScenarioPointManifest { get; set; }
public MCScenarioPointRegion CScenarioPointRegion { get; set; }
public ScenarioRegion ScenarioRegion { get; set; }
//fields used by the editor:
public bool HasChanged { get; set; } = false;
public List<string> SaveWarnings = null;
public YmtFile() : base(null, GameFileType.Ymt)
{
}
public YmtFile(RpfFileEntry entry) : base(entry, GameFileType.Ymt)
{
}
public void LoadRSC(byte[] data)
{
//direct load from a raw, compressed ymt resource file (openIV-compatible format)
RpfResourceFileEntry resentry = new RpfResourceFileEntry();
//hopefully this format has an RSC7 header...
uint rsc7 = BitConverter.ToUInt32(data, 0);
if (rsc7 == 0x37435352) //RSC7 header present!
{
int version = BitConverter.ToInt32(data, 4);
resentry.SystemFlags = BitConverter.ToUInt32(data, 8);
resentry.GraphicsFlags = BitConverter.ToUInt32(data, 12);
if (data.Length > 16)
{
int newlen = data.Length - 16; //trim the header from the data passed to the next step.
byte[] newdata = new byte[newlen];
Buffer.BlockCopy(data, 16, newdata, 0, newlen);
data = newdata;
}
else
{
data = null; //shouldn't happen... empty..
}
}
else
{
//direct load from file without the rpf header..
//assume it's in resource meta format
resentry.SystemFlags = RpfResourceFileEntry.GetFlagsFromSize(data.Length, 0);
resentry.GraphicsFlags = RpfResourceFileEntry.GetFlagsFromSize(0, 2); //graphics type 2 for ymt/meta
}
var oldresentry = RpfFileEntry as RpfResourceFileEntry;
if (oldresentry != null) //update the existing entry with the new one
{
oldresentry.SystemFlags = resentry.SystemFlags;
oldresentry.GraphicsFlags = resentry.GraphicsFlags;
resentry.Name = oldresentry.Name;
resentry.NameHash = oldresentry.NameHash;
resentry.NameLower = oldresentry.NameLower;
resentry.ShortNameHash = oldresentry.ShortNameHash;
}
else
{
RpfFileEntry = resentry; //just stick it in there for later...
}
data = ResourceBuilder.Decompress(data);
Load(data, resentry);
//Loaded = true;
}
public void Load(byte[] data, RpfFileEntry entry)
{
RpfFileEntry = entry;
Name = entry.Name;
FilePath = Name;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry != null)
{
ResourceDataReader rd = new ResourceDataReader(resentry, data);
Meta = rd.ReadBlock<Meta>();
var rootblock = Meta.GetRootBlock();
if (rootblock != null)
{
if (rootblock.StructureNameHash == MetaName.CScenarioPointRegion)
{
LoadScenarioPointRegion(Meta, rootblock);
}
}
Loaded = true;
return;
}
MemoryStream ms = new MemoryStream(data);
if (RbfFile.IsRBF(ms))
{
Rbf = new RbfFile();
var rbfstruct = Rbf.Load(ms);
if (rbfstruct.Name == "CMapParentTxds")
{
LoadMapParentTxds(rbfstruct);
}
Loaded = true;
return;
}
if (PsoFile.IsPSO(ms))
{
Pso = new PsoFile();
Pso.Load(ms);
//PsoTypes.EnsurePsoTypes(Pso);
var root = PsoTypes.GetRootEntry(Pso);
if (root != null)
{
if (root.NameHash == MetaName.CScenarioPointManifest)
{
LoadScenarioPointManifest(Pso);
}
}
Loaded = true;
return;
}
else
{
}
}
private void LoadMapParentTxds(RbfStructure rbfstruct)
{
FileFormat = YmtFileFormat.RBF;
ContentType = YmtFileContentType.MapParentTxds;
CMapParentTxds = new Dictionary<string, string>();
//StringBuilder sblist = new StringBuilder();
foreach(var child in rbfstruct.Children)
{
var childstruct = child as RbfStructure;
if ((childstruct != null) && (childstruct.Name == "txdRelationships"))
{
foreach (var txdrel in childstruct.Children)
{
var txdrelstruct = txdrel as RbfStructure;
if ((txdrelstruct != null) && (txdrelstruct.Name == "item"))
{
string parentstr = string.Empty;
string childstr = string.Empty;
foreach(var item in txdrelstruct.Children)
{
var itemstruct = item as RbfStructure;
if ((itemstruct != null))
{
var strbytes = itemstruct.Children[0] as RbfBytes;
string thisstr = string.Empty;
if (strbytes != null)
{
thisstr = Encoding.ASCII.GetString(strbytes.Value).Replace("\0", "");
}
switch (item.Name)
{
case "parent":
parentstr = thisstr;
break;
case "child":
childstr = thisstr;
break;
}
}
}
if((!string.IsNullOrEmpty(parentstr)) && (!string.IsNullOrEmpty(childstr)))
{
if (!CMapParentTxds.ContainsKey(childstr))
{
CMapParentTxds.Add(childstr, parentstr);
}
else
{
}
//sblist.AppendLine(childstr + ": " + parentstr);
}
}
}
}
}
//string alltxdmap = sblist.ToString();
//if (!string.IsNullOrEmpty(alltxdmap))
//{
//}
}
private void LoadScenarioPointManifest(PsoFile pso)
{
FileFormat = YmtFileFormat.PSO;
ContentType = YmtFileContentType.ScenarioPointManifest;
CScenarioPointManifest = new YmtScenarioPointManifest();
CScenarioPointManifest.Load(pso);
}
private void LoadScenarioPointRegion(Meta meta, MetaDataBlock rootblock)
{
FileFormat = YmtFileFormat.RSC;
ContentType = YmtFileContentType.ScenarioPointRegion;
var cdata = MetaTypes.ConvertData<CScenarioPointRegion>(rootblock.Data);
CScenarioPointRegion = new MCScenarioPointRegion();
CScenarioPointRegion.Ymt = this;
CScenarioPointRegion.Load(meta, cdata);
ScenarioRegion = new ScenarioRegion();
ScenarioRegion.Load(this);
//string stypes = MetaTypes.GetTypesInitString(meta);
//if (!string.IsNullOrEmpty(stypes))
//{ }
}
public byte[] Save()
{
switch (ContentType)
{
case YmtFileContentType.MapParentTxds: return SaveMapParentTxds();
case YmtFileContentType.ScenarioPointManifest: return SaveScenarioPointManifest();
case YmtFileContentType.ScenarioPointRegion: return SaveScenarioPointRegion();
}
return null;
}
private byte[] SaveMapParentTxds()
{
return null;
}
private byte[] SaveScenarioPointManifest()
{
return null;
}
private byte[] SaveScenarioPointRegion()
{
if (ScenarioRegion != null)
{
return ScenarioRegion.Save();
}
return null;
}
private void LogSaveWarning(string w)
{
if (SaveWarnings == null) SaveWarnings = new List<string>();
SaveWarnings.Add(w);
}
public override string ToString()
{
return RpfFileEntry.ToString();
}
}
public enum YmtFileFormat
{
Unknown = 0,
RSC = 1,
PSO = 2,
RBF = 3,
}
public enum YmtFileContentType
{
None = 0,
MapParentTxds = 1,
ScenarioPointManifest = 2,
ScenarioPointRegion = 3,
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class YmtScenarioPointManifest
{
public CScenarioPointManifest _Data;
public CScenarioPointManifest Data { get { return _Data; } set { _Data = value; } }
public CScenarioPointRegionDef[] RegionDefs { get; set; }
public CScenarioPointGroup[] Groups { get; set; }
public MetaHash[] InteriorNames { get; set; }
public void Load(PsoFile pso)
{
Data = PsoTypes.GetRootItem<CScenarioPointManifest>(pso);
RegionDefs = PsoTypes.ConvertDataArray<CScenarioPointRegionDef>(pso, _Data.RegionDefs);
Groups = PsoTypes.ConvertDataArray<CScenarioPointGroup>(pso, _Data.Groups);
InteriorNames = PsoTypes.GetHashArray(pso, _Data.InteriorNames);
}
}
}
File diff suppressed because it is too large Load Diff
+405
View File
@@ -0,0 +1,405 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpDX;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class YnvFile : GameFile, PackedFile, BasePathData
{
public NavMesh Nav { get; set; }
public List<Vector3> Vertices { get; set; }
public List<ushort> Indices { get; set; }
public List<YnvPoly> Polys { get; set; }
public VertexTypePC[] TriangleVerts { get; set; }
public Vector4[] NodePositions { get; set; }
//fields used by the editor:
public bool HasChanged { get; set; } = false;
public List<string> SaveWarnings = null;
public int AreaID
{
get
{
return (int)(Nav?.AreaID ?? 0);
}
}
public YnvFile() : base(null, GameFileType.Ynv)
{
}
public YnvFile(RpfFileEntry entry) : base(entry, GameFileType.Ynv)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
Nav = rd.ReadBlock<NavMesh>();
if ((Nav != null) && (Nav.SectorTree != null))
{
if (Nav.Vertices != null)
{
Vector3 posoffset = Nav.SectorTree.AABBMin.XYZ();
Vector3 aabbsize = Nav.AABBSize;
var verts = Nav.Vertices.GetFullList();
Vertices = new List<Vector3>(verts.Count);
for (int i = 0; i < verts.Count; i++)
{
var ov = verts[i].ToVector3();
Vertices.Add(posoffset + ov * aabbsize);
}
}
if (Nav.Indices != null)
{
Indices = Nav.Indices.GetFullList();
}
if (Nav.Polys != null)
{
var polys = Nav.Polys.GetFullList();
Polys = new List<YnvPoly>(polys.Count);
for (int i = 0; i < polys.Count; i++)
{
YnvPoly poly = new YnvPoly();
poly.Init(this, polys[i]);
poly.Index = i;
Polys.Add(poly);
//calc poly center.
if ((Indices == null) || (Vertices == null))
{ continue; }
var vc = Vertices.Count;
var ic = poly._RawData.IndexCount;
var startid = poly._RawData.IndexID;
var endid = startid + ic;
if (startid >= Indices.Count)
{ continue; }
if (endid > Indices.Count)
{ continue; }
Vector3 pcenter = Vector3.Zero;
float pcount = 0.0f;
for (int id = startid; id < endid; id++)
{
var ind = Indices[id];
if(ind>=vc)
{ continue; }
pcenter += Vertices[ind];
pcount += 1.0f;
}
poly.Position = pcenter * (1.0f / pcount);
}
}
}
UpdateAllNodePositions();
UpdateTriangleVertices();
Loaded = true;
LoadQueued = true;
}
public bool RemovePoly(YnvPoly poly)
{
return false;
}
public void UpdateAllNodePositions()
{
if (Nav == null) return;
if (Nav.Portals == null) return;
int cnt = Nav.Portals?.Length ?? 0;
if (cnt <= 0)
{
NodePositions = null;
return;
}
Vector3 posoffset = Nav.SectorTree.AABBMin.XYZ();
Vector3 aabbsize = Nav.AABBSize;
var np = new Vector4[cnt];
for (int i = 0; i < cnt; i++)
{
var portal = Nav.Portals[i];
var pv = portal.Position1.ToVector3();
//var pv = portal.Position2.ToVector3();
np[i] = new Vector4(posoffset + pv * aabbsize, 1.0f);
}
NodePositions = np;
}
public void UpdateTriangleVertices()
{
if (Nav == null) return;
if (Nav.Polys == null) return;
if (Nav.Vertices == null) return;
//need position and colour for each vertex.
//render as a triangle list... (no indices needed)
//go through the nav mesh polys and generate verts to render...
if ((Vertices == null) || (Vertices.Count == 0)) return;
if ((Indices == null) || (Indices.Count == 0)) return;
if ((Polys == null) || (Polys.Count == 0)) return;
int vc = Vertices.Count;
List<VertexTypePC> rverts = new List<VertexTypePC>();
foreach (var ypoly in Polys)
{
var poly = ypoly.RawData;
var colour = ypoly.GetColour();
var colourval = (uint)colour.ToRgba();
var ic = poly.IndexCount;
var startid = poly.IndexID;
var endid = startid + ic;
if (startid >= Indices.Count)
{ continue; }
if (endid > Indices.Count)
{ continue; }
if(ic<3)
{ continue; }//not enough verts to make a triangle...
if (ic > 15)
{ }
VertexTypePC p0 = new VertexTypePC();
VertexTypePC p1 = new VertexTypePC();
VertexTypePC p2 = new VertexTypePC();
p0.Colour = colourval;
p1.Colour = colourval;
p2.Colour = colourval;
var startind = Indices[startid];
if (startind >= vc)
{ continue; }
p0.Position = Vertices[startind];
//build triangles for the poly.
int tricount = ic - 2;
for (int t = 0; t < tricount; t++)
{
int tid = startid + t;
int ind1 = Indices[tid + 1];
int ind2 = Indices[tid + 2];
if ((ind1 >= vc) || (ind2 >= vc))
{ continue; }
p1.Position = Vertices[ind1];
p2.Position = Vertices[ind2];
rverts.Add(p0);
rverts.Add(p1);
rverts.Add(p2);
}
}
TriangleVerts = rverts.ToArray();
}
public VertexTypePC[] GetPathVertices()
{
return null;
}
public VertexTypePC[] GetTriangleVertices()
{
return TriangleVerts;
}
public Vector4[] GetNodePositions()
{
return NodePositions;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class YnvPoly
{
public NavMeshPoly _RawData;
public YnvFile Ynv { get; set; }
public NavMeshPoly RawData { get { return _RawData; } set { _RawData = value; } }
public ushort AreaID { get { return _RawData.AreaID; } }
public bool B00_AvoidUnk { get { return (_RawData.Unknown_00h & 1) > 0; } }
public bool B01_AvoidUnk { get { return (_RawData.Unknown_00h & 2) > 0; } }
public bool B02_IsFootpath { get { return (_RawData.Unknown_00h & 4) > 0; } }
public bool B03_IsUnderground { get { return (_RawData.Unknown_00h & 8) > 0; } }
//public bool B04_Unused { get { return (_RawData.Unknown_00h & 16) > 0; } }
//public bool B05_Unused { get { return (_RawData.Unknown_00h & 32) > 0; } }
public bool B06_SteepSlope { get { return (_RawData.Unknown_00h & 64) > 0; } }
public bool B07_IsWater { get { return (_RawData.Unknown_00h & 128) > 0; } }
public bool B08_UndergroundUnk1 { get { return (_RawData.Unknown_24h.Value & 1) > 0; } }
public bool B09_UndergroundUnk2 { get { return (_RawData.Unknown_24h.Value & 2) > 0; } }
public bool B10_UndergroundUnk3 { get { return (_RawData.Unknown_24h.Value & 4) > 0; } }
public bool B11_UndergroundUnk4 { get { return (_RawData.Unknown_24h.Value & 8) > 0; } }
//public bool B12_Unused { get { return (_RawData.Unknown_24h.Value & 16) > 0; } }
public bool B13_HasPathNode { get { return (_RawData.Unknown_24h.Value & 32) > 0; } }
public bool B14_IsInterior { get { return (_RawData.Unknown_24h.Value & 64) > 0; } }
public bool B15_InteractionUnk { get { return (_RawData.Unknown_24h.Value & 128) > 0; } }
//public bool B16_Unused { get { return (_RawData.Unknown_24h.Value & 256) > 0; } }
public bool B17_IsFlatGround { get { return (_RawData.Unknown_24h.Value & 512) > 0; } }
public bool B18_IsRoad { get { return (_RawData.Unknown_24h.Value & 1024) > 0; } }
public bool B19_IsCellEdge { get { return (_RawData.Unknown_24h.Value & 2048) > 0; } }
public bool B20_IsTrainTrack { get { return (_RawData.Unknown_24h.Value & 4096) > 0; } }
public bool B21_IsShallowWater { get { return (_RawData.Unknown_24h.Value & 8192) > 0; } }
public bool B22_FootpathUnk1 { get { return (_RawData.Unknown_24h.Value & 16384) > 0; } }
public bool B23_FootpathUnk2 { get { return (_RawData.Unknown_24h.Value & 32768) > 0; } }
public bool B24_FootpathMall { get { return (_RawData.Unknown_24h.Value & 65536) > 0; } }
public bool B25_SlopeSouth { get { return (_RawData.Unknown_28h.Value & 65536) > 0; } }
public bool B26_SlopeSouthEast { get { return (_RawData.Unknown_28h.Value & 131072) > 0; } }
public bool B27_SlopeEast { get { return (_RawData.Unknown_28h.Value & 262144) > 0; } }
public bool B28_SlopeNorthEast { get { return (_RawData.Unknown_28h.Value & 524288) > 0; } }
public bool B29_SlopeNorth { get { return (_RawData.Unknown_28h.Value & 1048576) > 0; } }
public bool B30_SlopeNorthWest { get { return (_RawData.Unknown_28h.Value & 2097152) > 0; } }
public bool B31_SlopeWest { get { return (_RawData.Unknown_28h.Value & 4194304) > 0; } }
public bool B32_SlopeSouthWest { get { return (_RawData.Unknown_28h.Value & 8388608) > 0; } }
public bool B33_PortalUnk1 { get { return (_RawData.PartUnk2 & 1) > 0; } }
public bool B34_PortalUnk2 { get { return (_RawData.PartUnk2 & 2) > 0; } }
public bool B35_PortalUnk3 { get { return (_RawData.PartUnk2 & 4) > 0; } }
public bool B36_PortalUnk4 { get { return (_RawData.PartUnk2 & 8) > 0; } }
public byte HeuristicXUnk { get { return (byte)_RawData.Unknown_28h_8a; } }
public byte HeuristicYUnk { get { return (byte)_RawData.Unknown_28h_8b; } }
public Vector3 Position { get; set; }
public int Index { get; set; }
public void Init(YnvFile ynv, NavMeshPoly poly)
{
Ynv = ynv;
RawData = poly;
}
public Color4 GetColour()
{
var colour = new Color4();
var u0 = _RawData.Unknown_00h;
if ((u0 & 1) > 0) colour.Red += 0.01f;//avoid? loiter?
if ((u0 & 2) > 0) colour.Red += 0.01f; //avoid?
if ((u0 & 4) > 0) colour.Green += 0.25f; //ped/footpath
if ((u0 & 8) > 0) colour.Green += 0.02f; //underground?
////if ((u0 & 16) > 0) colour.Red += 1.0f; //not used?
////if ((u0 & 32) > 0) colour.Green += 1.0f;//not used?
if ((u0 & 64) > 0) colour.Red += 0.25f; //steep slope
if ((u0 & 128) > 0) colour.Blue += 0.25f; //water
var u2 = _RawData.Unknown_24h.Value;
//colour.Green = (u2 & 15) / 15.0f; //maybe underground amount..?
//if ((u2 & 1) > 0) colour.Blue += 1.0f; //peds interact with something? underground?
//if ((u2 & 2) > 0) colour.Green += 1.0f;//underneath something?
//if ((u2 & 4) > 0) colour.Red += 0.5f;//peds interact with something..? underground?
//if ((u2 & 8) > 0) colour.Red += 0.5f; //underground?
//if ((u2 & 16) > 0) colour.Red += 1.0f; //not used..
//if ((u2 & 32) > 0) colour.Green += 1.0f;//use path node?
if ((u2 & 64) > 0) colour.Blue += 0.1f; //is interior?
//if ((u2 & 128) > 0) colour.Red += 1.0f; //interacting areas? veg branches, roofs, vents, worker areas?
//if ((u2 & 256) > 0) colour.Green += 1.0f; //not used?
if ((u2 & 512) > 0) colour.Green += 0.1f;//is flat ground? ped-navigable?
if ((u2 & 1024) > 0) colour.Blue += 0.03f;//is a road
//if ((u2 & 2048) > 0) colour.Green += 1.0f; //poly is on a cell edge
if ((u2 & 4096) > 0) colour.Green += 0.75f; //is a train track
if ((u2 & 8192) > 0) colour.Blue += 0.75f;//shallow water/moving water
if ((u2 & 16384) > 0) colour.Red += 0.2f; //footpaths/beach - peds walking?
if ((u2 & 32768) > 0) colour.Blue += 0.2f; //footpaths - special?
if ((u2 & 65536) > 0) colour.Green = 0.2f;//footpaths - mall areas? eg mall, vinewood blvd
//if (u2 >= 131072) { }//other bits unused
var u5 = _RawData.Unknown_28h.Value; //32 bits
//colour.Red = poly.Unknown_28h_8a / 255.0f; //heuristic vals..?
//colour.Green = poly.Unknown_28h_8b / 255.0f; //heuristic vals..?
//if ((u5 & 65536) > 0) colour.Red += 1.0f; //slope facing -Y (south)
//if ((u5 & 131072) > 0) colour.Blue += 1.0f; //slope facing +X,-Y (southeast)
//if ((u5 & 262144) > 0) colour.Green += 1.0f; //slope facing +X (east)
//if ((u5 & 524288) > 0) colour.Red += 1.0f; //slope facing +X,+Y (northeast)
//if ((u5 & 1048576) > 0) colour.Green += 1.0f; //slope facing +Y (north)
//if ((u5 & 2097152) > 0) colour.Blue += 1.0f; //slope facing -X,+Y (northwest)
//if ((u5 & 4194304) > 0) colour.Green += 1.0f; //slope facing -X (west)
//if ((u5 & 8388608) > 0) colour.Red += 1.0f; //slope facing -X,-Y (southwest)
//if (u5 >= 16777216) { } //other bits unused
var u1 = _RawData.PartUnk2;
//if ((u1 & 1) > 0) colour.Red += 1.0f; //portal - don't interact?
//if ((u1 & 2) > 0) colour.Green += 1.0f; //portal - ladder/fence interaction?
//if ((u1 & 4) > 0) colour.Blue += 1.0f; //portal - fence interaction / go away from?
//if ((u1 & 8) > 0) colour.Red += 1.0f;//something file-specific? portal index related?
colour.Alpha = 0.75f;
return colour;
}
public override string ToString()
{
return AreaID.ToString() + ", " + Index.ToString();
}
}
}
+106
View File
@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YptFile : GameFile, PackedFile
{
public ParticleEffectsList PtfxList { get; set; }
public Dictionary<uint, Drawable> DrawableDict { get; set; }
public string ErrorMessage { get; set; }
public YptFile() : base(null, GameFileType.Ypt)
{
}
public YptFile(RpfFileEntry entry) : base(entry, GameFileType.Ypt)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
//MemoryUsage = 0;
try
{
PtfxList = rd.ReadBlock<ParticleEffectsList>();
//Drawable.Owner = this;
//MemoryUsage += Drawable.MemoryUsage; //uses decompressed filesize now...
}
catch (Exception ex)
{
ErrorMessage = ex.ToString();
}
var dDict = PtfxList?.DrawableDictionary;
if ((dDict != null) &&
(dDict.Drawables != null) &&
(dDict.Drawables.data_items != null) &&
(dDict.Hashes != null))
{
DrawableDict = new Dictionary<uint, Drawable>();
var drawables = dDict.Drawables.data_items;
var hashes = dDict.Hashes;
for (int i = 0; (i < drawables.Length) && (i < hashes.Length); i++)
{
var drawable = drawables[i];
var hash = hashes[i];
DrawableDict[hash] = drawable;
drawable.Owner = this;
}
for (int i = 0; (i < drawables.Length) && (i < hashes.Length); i++)
{
var drawable = drawables[i];
var hash = hashes[i];
if ((drawable.Name == null) || (drawable.Name.EndsWith("#dd")))
{
string hstr = JenkIndex.TryGetString(hash);
if (!string.IsNullOrEmpty(hstr))
{
drawable.Name = hstr;
}
else
{
drawable.Name = "0x" + hash.ToString("X").PadLeft(8, '0');
}
}
}
}
Loaded = true;
}
}
}
+49
View File
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YtdFile : GameFile, PackedFile
{
public TextureDictionary TextureDict { get; set; }
public YtdFile() : base(null, GameFileType.Ytd)
{
}
public YtdFile(RpfFileEntry entry) : base(entry, GameFileType.Ytd)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
TextureDict = rd.ReadBlock<TextureDictionary>();
//MemoryUsage = 0; //uses decompressed file size now..
//if (TextureDict != null)
//{
// MemoryUsage += TextureDict.MemoryUsage;
//}
}
}
}
+265
View File
@@ -0,0 +1,265 @@
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 YtypFile : PackedFile
{
public RpfFileEntry FileEntry { get; set; }
public Meta Meta { get; set; }
public PsoFile Pso { get; set; }
public RbfFile Rbf { get; set; }
public CMapTypes CMapTypes { get; set; }
//public CBaseArchetypeDef[] CBaseArchetypeDefs { get; set; }
//public CTimeArchetypeDef[] CTimeArchetypeDefs { get; set; }
//public CMloArchetypeDef[] CMloArchetypeDefs { get; set; }
public CExtensionDefAudioEmitter[] AudioEmitters { get; set; }
//public CEntityDef[] CEntityDefs { get; set; }
public CCompositeEntityType[] CompositeEntityTypes { get; set; }
public uint NameHash { get; set; }
public string[] Strings { get; set; }
public Archetype[] AllArchetypes { get; set; }
public MetaWrapper[] Extensions { get; set; }
public override string ToString()
{
return (FileEntry != null) ? FileEntry.Name : string.Empty;
}
public void Load(byte[] data, RpfFileEntry entry)
{
FileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
MemoryStream ms = new MemoryStream(data);
if (RbfFile.IsRBF(ms))
{
Rbf = new RbfFile();
Rbf.Load(ms);
}
else if (PsoFile.IsPSO(ms))
{
Pso = new PsoFile();
Pso.Load(ms);
//PsoTypes.EnsurePsoTypes(Pso);
}
else
{
}
return;
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
Meta = rd.ReadBlock<Meta>();
CMapTypes = MetaTypes.GetTypedData<CMapTypes>(Meta, MetaName.CMapTypes);
List<Archetype> allarchs = new List<Archetype>();
var ptrs = MetaTypes.GetPointerArray(Meta, CMapTypes.archetypes);
if (ptrs != null)
{
for (int i = 0; i < ptrs.Length; i++)
{
var ptr = ptrs[i];
int blocki = ptr.BlockID - 1;
int offset = ptr.ItemOffset * 16;//block data size...
if (blocki >= Meta.DataBlocks.Count)
{ continue; }
var block = Meta.DataBlocks[blocki];
if ((offset < 0) || (block.Data == null) || (offset >= block.Data.Length))
{ continue; }
var ba = new Archetype();
switch (block.StructureNameHash)
{
case MetaName.CBaseArchetypeDef:
var basearch = PsoTypes.ConvertDataRaw<CBaseArchetypeDef>(block.Data, offset);
ba.Init(this, basearch);
ba.Extensions = MetaTypes.GetExtensions(Meta, basearch.extensions);
break;
case MetaName.CTimeArchetypeDef:
var timearch = PsoTypes.ConvertDataRaw<CTimeArchetypeDef>(block.Data, offset);
ba.Init(this, timearch);
ba.Extensions = MetaTypes.GetExtensions(Meta, timearch.CBaseArchetypeDef.extensions);
break;
case MetaName.CMloArchetypeDef:
var mloarch = PsoTypes.ConvertDataRaw<CMloArchetypeDef>(block.Data, offset);
ba.Init(this, mloarch);
ba.Extensions = MetaTypes.GetExtensions(Meta, mloarch.CBaseArchetypeDef.extensions);
MloArchetypeData mlod = new MloArchetypeData();
mlod.entities = MetaTypes.ConvertDataArray<CEntityDef>(Meta, MetaName.CEntityDef, mloarch.entities);
mlod.rooms = MetaTypes.ConvertDataArray<CMloRoomDef>(Meta, MetaName.CMloRoomDef, mloarch.rooms);
mlod.portals = MetaTypes.ConvertDataArray<CMloPortalDef>(Meta, MetaName.CMloPortalDef, mloarch.portals);
mlod.entitySets = MetaTypes.ConvertDataArray<CMloEntitySet>(Meta, MetaName.CMloEntitySet, mloarch.entitySets);
mlod.timeCycleModifiers = MetaTypes.ConvertDataArray<CMloTimeCycleModifier>(Meta, MetaName.CMloTimeCycleModifier, mloarch.timeCycleModifiers);
ba.MloData = mlod;
//if (mlod.entities != null)
//{
// for (int e = 0; e < mlod.entities.Length; e++)
// {
// EnsureEntityExtensions(Meta, ref mlod.entities[e]);
// }
//}
break;
default:
continue;
}
allarchs.Add(ba);
}
}
AllArchetypes = allarchs.ToArray();
Extensions = MetaTypes.GetExtensions(Meta, CMapTypes.extensions);
if (Extensions != null)
{ }
AudioEmitters = MetaTypes.GetTypedDataArray<CExtensionDefAudioEmitter>(Meta, MetaName.CExtensionDefAudioEmitter);
if (AudioEmitters != null)
{ }
//CEntityDefs = MetaTypes.GetTypedDataArray<CEntityDef>(Meta, MetaName.CEntityDef);
CompositeEntityTypes = MetaTypes.ConvertDataArray<CCompositeEntityType>(Meta, MetaName.CCompositeEntityType, CMapTypes.compositeEntityTypes);
if (CompositeEntityTypes != null)
{ }
NameHash = CMapTypes.name;
if (NameHash == 0)
{
int ind = entry.NameLower.LastIndexOf('.');
if (ind > 0)
{
NameHash = JenkHash.GenHash(entry.NameLower.Substring(0, ind));
}
else
{
NameHash = JenkHash.GenHash(entry.NameLower);
}
}
Strings = MetaTypes.GetStrings(Meta);
if (Strings != null)
{
foreach (string str in Strings)
{
JenkIndex.Ensure(str); //just shove them in there
}
}
foreach (var block in Meta.DataBlocks)
{
switch(block.StructureNameHash)
{
case MetaName.CMapTypes:
case MetaName.CTimeArchetypeDef:
case MetaName.CBaseArchetypeDef:
case MetaName.CMloArchetypeDef:
case MetaName.CMloTimeCycleModifier:
case MetaName.CMloRoomDef:
case MetaName.CMloPortalDef:
case MetaName.CMloEntitySet:
case MetaName.CEntityDef:
case MetaName.CExtensionDefParticleEffect:
case MetaName.CExtensionDefAudioCollisionSettings:
case MetaName.CExtensionDefSpawnPoint:
case MetaName.CExtensionDefSpawnPointOverride:
case MetaName.CExtensionDefExplosionEffect:
case MetaName.CExtensionDefAudioEmitter:
case MetaName.CExtensionDefLadder:
case MetaName.CExtensionDefBuoyancy:
case MetaName.CExtensionDefExpression:
case MetaName.CExtensionDefLightShaft:
case MetaName.CExtensionDefLightEffect:
case MetaName.CExtensionDefDoor:
case MetaName.CExtensionDefWindDisturbance:
case MetaName.CExtensionDefProcObject:
case MetaName.CLightAttrDef:
case MetaName.STRING:
//case MetaName.SectionUNKNOWN2:
//case MetaName.SectionUNKNOWN3:
//case MetaName.SectionUNKNOWN8:
case MetaName.POINTER:
case MetaName.UINT:
case MetaName.VECTOR4:
break;
default:
break;
}
}
//MetaTypes.ParseMetaData(Meta);
//RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
//if (resentry == null)
//{
// throw new Exception("File entry wasn't a resource! (is it binary data?)");
//}
//ResourceDataReader rd = new ResourceDataReader(resentry, data);
//Meta = rd.ReadBlock<Meta>();
//MetaTypes.EnsureMetaTypes(Meta);
//MetaTypes.ParseMetaData(Meta);
}
}
}
+54
View File
@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YvrFile : GameFile, PackedFile
{
public VehicleRecordList Records { get; set; }
public YvrFile() : base(null, GameFileType.Yvr)
{
}
public YvrFile(RpfFileEntry entry) : base(entry, GameFileType.Yvr)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
//MemoryUsage = 0;
try
{
Records = rd.ReadBlock<VehicleRecordList>();
}
catch (Exception ex)
{
string err = ex.ToString();
}
Loaded = true;
}
}
}
+54
View File
@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YwrFile : GameFile, PackedFile
{
public WaypointRecordList Waypoints { get; set; }
public YwrFile() : base(null, GameFileType.Ywr)
{
}
public YwrFile(RpfFileEntry entry) : base(entry, GameFileType.Ywr)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
//MemoryUsage = 0;
try
{
Waypoints = rd.ReadBlock<WaypointRecordList>();
}
catch (Exception ex)
{
string err = ex.ToString();
}
Loaded = true;
}
}
}
+74
View File
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public abstract class GameFile : Cacheable<GameFileCacheKey>
{
public volatile bool Loaded = false;
public volatile bool LoadQueued = false;
public RpfFileEntry RpfFileEntry { get; set; }
public string Name { get; set; }
public string FilePath { get; set; } //used by the project form.
public GameFileType Type { get; set; }
public GameFile(RpfFileEntry entry, GameFileType type)
{
RpfFileEntry = entry;
Type = type;
MemoryUsage = (entry != null) ? entry.FileSize : 0;
if (entry is RpfResourceFileEntry)
{
var resent = entry as RpfResourceFileEntry;
var newuse = resent.SystemSize + resent.GraphicsSize;
MemoryUsage = newuse;
}
else if (entry is RpfBinaryFileEntry)
{
var binent = entry as RpfBinaryFileEntry;
var newuse = binent.FileUncompressedSize;
if (newuse > MemoryUsage)
{
MemoryUsage = newuse;
}
}
else
{
}
}
public override string ToString()
{
return (string.IsNullOrEmpty(Name)) ? JenkIndex.GetString(Key.Hash) : Name;
}
}
public enum GameFileType : int
{
Ydd = 0,
Ydr = 1,
Yft = 2,
Ymap = 3,
Ymf = 4,
Ymt = 5,
Ytd = 6,
Ytyp = 7,
Ybn = 8,
Ycd = 9,
Ypt = 10,
Ynd = 11,
Ynv = 12,
Rel = 13,
Ywr = 14,
Yvr = 15,
}
}
File diff suppressed because it is too large Load Diff
+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(); }
}
}
+191
View File
@@ -0,0 +1,191 @@
using SharpDX;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))]
public class Archetype
{
public MetaHash Hash { get; set; }
public YtypFile Ytyp { get; set; }
public CBaseArchetypeDef BaseArchetype { get; set; }
public CTimeArchetypeDef TimeArchetype { get; set; }
public CMloArchetypeDef MloArchetype { get; set; }
public MetaHash DrawableDict { get; set; }
public MetaHash TextureDict { get; set; }
public MetaHash ClipDict { get; set; }
public Vector3 BBMin { get; set; }
public Vector3 BBMax { get; set; }
public Vector3 BSCenter { get; set; }
public float BSRadius { get; set; }
public bool IsTimeArchetype { get; set; }
public bool IsMloArchetype { get; set; }
public float LodDist { get; set; }
public MloArchetypeData MloData { get; set; }
public MetaWrapper[] Extensions { get; set; }
public TimedArchetypeTimes Times { get; set; }
public string Name
{
get
{
if (IsTimeArchetype) return TimeArchetype.CBaseArchetypeDef.name.ToString();
if (IsMloArchetype) return MloArchetype.CBaseArchetypeDef.name.ToString();
return BaseArchetype.name.ToString();
}
}
public string AssetName
{
get
{
if (IsTimeArchetype) return TimeArchetype.CBaseArchetypeDef.assetName.ToString();
if (IsMloArchetype) return MloArchetype.CBaseArchetypeDef.assetName.ToString();
return BaseArchetype.assetName.ToString();
}
}
public void Init(YtypFile ytyp, CBaseArchetypeDef arch)
{
Hash = arch.assetName;
if (Hash.Hash == 0) Hash = arch.name;
Ytyp = ytyp;
BaseArchetype = arch;
DrawableDict = arch.drawableDictionary;
TextureDict = arch.textureDictionary;
ClipDict = arch.clipDictionary;
BBMin = arch.bbMin;
BBMax = arch.bbMax;
BSCenter = arch.bsCentre;
BSRadius = arch.bsRadius;
IsTimeArchetype = false;
IsMloArchetype = false;
LodDist = arch.lodDist;
}
public void Init(YtypFile ytyp, CTimeArchetypeDef arch)
{
Hash = arch.CBaseArchetypeDef.assetName;
if (Hash.Hash == 0) Hash = arch.CBaseArchetypeDef.name;
Ytyp = ytyp;
TimeArchetype = arch;
DrawableDict = arch.CBaseArchetypeDef.drawableDictionary;
TextureDict = arch.CBaseArchetypeDef.textureDictionary;
ClipDict = arch.CBaseArchetypeDef.clipDictionary;
BBMin = arch.CBaseArchetypeDef.bbMin;
BBMax = arch.CBaseArchetypeDef.bbMax;
BSCenter = arch.CBaseArchetypeDef.bsCentre;
BSRadius = arch.CBaseArchetypeDef.bsRadius;
IsTimeArchetype = true;
IsMloArchetype = false;
LodDist = arch.CBaseArchetypeDef.lodDist;
Times = new TimedArchetypeTimes(arch.timeFlags);
}
public void Init(YtypFile ytyp, CMloArchetypeDef arch)
{
Hash = arch.CBaseArchetypeDef.assetName;
if (Hash.Hash == 0) Hash = arch.CBaseArchetypeDef.name;
Ytyp = ytyp;
MloArchetype = arch;
DrawableDict = arch.CBaseArchetypeDef.drawableDictionary;
TextureDict = arch.CBaseArchetypeDef.textureDictionary;
ClipDict = arch.CBaseArchetypeDef.clipDictionary;
BBMin = arch.CBaseArchetypeDef.bbMin;
BBMax = arch.CBaseArchetypeDef.bbMax;
BSCenter = arch.CBaseArchetypeDef.bsCentre;
BSRadius = arch.CBaseArchetypeDef.bsRadius;
IsTimeArchetype = false;
IsMloArchetype = true;
LodDist = arch.CBaseArchetypeDef.lodDist;
}
public bool IsActive(float hour)
{
if (Times == null) return true;
//if (Times.ExtraFlag) hour -= 0.5f;
//if (hour < 0.0f) hour += 24.0f;
int h = ((int)hour) % 24;
if ((h < 0) || (h > 23)) return true;
return Times.ActiveHours[h];
}
public override string ToString()
{
if (IsTimeArchetype) return TimeArchetype.ToString();
if (IsMloArchetype) return MloArchetype.ToString();
return BaseArchetype.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))]
public class MloArchetypeData
{
public CEntityDef[] entities { get; set; }
public CMloRoomDef[] rooms { get; set; }
public CMloPortalDef[] portals { get; set; }
public CMloEntitySet[] entitySets { get; set; }
public CMloTimeCycleModifier[] timeCycleModifiers { get; set; }
}
[TypeConverter(typeof(ExpandableObjectConverter))]
public class MloEntityData
{
public YmapEntityDef[] AllEntities { get; set; }
public void CreateYmapEntities(YmapEntityDef owner, MloArchetypeData mlod)
{
if (owner == null) return;
if (mlod.entities == null) return;
AllEntities = new YmapEntityDef[mlod.entities.Length];
for (int i = 0; i < mlod.entities.Length; i++)
{
YmapEntityDef e = new YmapEntityDef(null, i, ref mlod.entities[i]);
e.MloParent = owner;
e.Position = owner.Position + owner.Orientation.Multiply(e.Position);
e.Orientation = Quaternion.Multiply(owner.Orientation, e.Orientation);
e.UpdateWidgetPosition();
e.UpdateWidgetOrientation();
if ((owner.Orientation != Quaternion.Identity)&&(owner.Orientation.Z!=1.0f))
{ }
AllEntities[i] = e;
}
}
}
[TypeConverter(typeof(ExpandableObjectConverter))]
public class TimedArchetypeTimes
{
public uint TimeFlags { get; set; }
public bool[] ActiveHours { get; set; }
public string[] ActiveHoursText { get; set; }
public bool ExtraFlag { get; set; }
public TimedArchetypeTimes(uint timeFlags)
{
TimeFlags = timeFlags;
ActiveHours = new bool[24];
ActiveHoursText = new string[24];
for (int i = 0; i < 24; i++)
{
bool v = ((timeFlags >> i) & 1) == 1;
ActiveHours[i] = v;
int nxth = (i < 23) ? (i + 1) : 0;
string hrs = string.Format("{0:00}:00 - {1:00}:00", i, nxth);
ActiveHoursText[i] = (hrs + (v ? " - On" : " - Off"));
}
ExtraFlag = ((timeFlags >> 24) & 1) == 1;
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+483
View File
@@ -0,0 +1,483 @@
/*
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
using SharpDX;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public enum Endianess
{
LittleEndian,
BigEndian
}
public enum DataType
{
Byte = 0,
Int16 = 1,
Int32 = 2,
Int64 = 3,
Uint16 = 4,
Uint32 = 5,
Uint64 = 6,
Float = 7,
Double = 8,
String = 9,
}
public class DataReader
{
private Stream baseStream;
/// <summary>
/// Gets or sets the endianess of the underlying stream.
/// </summary>
public Endianess Endianess
{
get;
set;
}
/// <summary>
/// Gets the length of the underlying stream.
/// </summary>
public virtual long Length
{
get
{
return baseStream.Length;
}
}
/// <summary>
/// Gets or sets the position within the underlying stream.
/// </summary>
public virtual long Position
{
get
{
return baseStream.Position;
}
set
{
baseStream.Position = value;
}
}
/// <summary>
/// Initializes a new data reader for the specified stream.
/// </summary>
public DataReader(Stream stream, Endianess endianess = Endianess.LittleEndian)
{
this.baseStream = stream;
this.Endianess = endianess;
}
/// <summary>
/// Reads data from the underlying stream. This is the only method that directly accesses
/// the data in the underlying stream.
/// </summary>
protected virtual byte[] ReadFromStream(int count, bool ignoreEndianess = false)
{
var buffer = new byte[count];
baseStream.Read(buffer, 0, count);
// handle endianess
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
{
Array.Reverse(buffer);
}
return buffer;
}
/// <summary>
/// Reads a byte.
/// </summary>
public byte ReadByte()
{
return ReadFromStream(1)[0];
}
/// <summary>
/// Reads a sequence of bytes.
/// </summary>
public byte[] ReadBytes(int count)
{
return ReadFromStream(count, true);
}
/// <summary>
/// Reads a signed 16-bit value.
/// </summary>
public short ReadInt16()
{
return BitConverter.ToInt16(ReadFromStream(2), 0);
}
/// <summary>
/// Reads a signed 32-bit value.
/// </summary>
public int ReadInt32()
{
return BitConverter.ToInt32(ReadFromStream(4), 0);
}
/// <summary>
/// Reads a signed 64-bit value.
/// </summary>
public long ReadInt64()
{
return BitConverter.ToInt64(ReadFromStream(8), 0);
}
/// <summary>
/// Reads an unsigned 16-bit value.
/// </summary>
public ushort ReadUInt16()
{
return BitConverter.ToUInt16(ReadFromStream(2), 0);
}
/// <summary>
/// Reads an unsigned 32-bit value.
/// </summary>
public uint ReadUInt32()
{
return BitConverter.ToUInt32(ReadFromStream(4), 0);
}
/// <summary>
/// Reads an unsigned 64-bit value.
/// </summary>
public ulong ReadUInt64()
{
return BitConverter.ToUInt64(ReadFromStream(8), 0);
}
/// <summary>
/// Reads a single precision floating point value.
/// </summary>
public float ReadSingle()
{
return BitConverter.ToSingle(ReadFromStream(4), 0);
}
/// <summary>
/// Reads a double precision floating point value.
/// </summary>
public double ReadDouble()
{
return BitConverter.ToDouble(ReadFromStream(8), 0);
}
/// <summary>
/// Reads a string.
/// </summary>
public string ReadString()
{
var bytes = new List<byte>();
var temp = ReadFromStream(1)[0];
while (temp != 0)
{
bytes.Add(temp);
temp = ReadFromStream(1)[0];
}
return Encoding.UTF8.GetString(bytes.ToArray());
}
public Vector3 ReadVector3()
{
Vector3 v = new Vector3();
v.X = ReadSingle();
v.Y = ReadSingle();
v.Z = ReadSingle();
return v;
}
public Vector4 ReadVector4()
{
Vector4 v = new Vector4();
v.X = ReadSingle();
v.Y = ReadSingle();
v.Z = ReadSingle();
v.W = ReadSingle();
return v;
}
public Matrix ReadMatrix()
{
Matrix m = new Matrix();
m.M11 = ReadSingle();
m.M21 = ReadSingle();
m.M31 = ReadSingle();
m.M41 = ReadSingle();
m.M12 = ReadSingle();
m.M22 = ReadSingle();
m.M32 = ReadSingle();
m.M42 = ReadSingle();
m.M13 = ReadSingle();
m.M23 = ReadSingle();
m.M33 = ReadSingle();
m.M43 = ReadSingle();
m.M14 = ReadSingle();
m.M24 = ReadSingle();
m.M34 = ReadSingle();
m.M44 = ReadSingle();
return m;
}
//TODO: put this somewhere else...
public static uint SizeOf(DataType type)
{
switch (type)
{
default:
case DataType.Byte: return 1;
case DataType.Int16: return 2;
case DataType.Int32: return 4;
case DataType.Int64: return 8;
case DataType.Uint16: return 2;
case DataType.Uint32: return 4;
case DataType.Uint64: return 8;
case DataType.Float: return 4;
case DataType.Double: return 8;
case DataType.String: return 0; //how long is a string..?
}
}
}
public class DataWriter
{
private Stream baseStream;
/// <summary>
/// Gets or sets the endianess of the underlying stream.
/// </summary>
public Endianess Endianess
{
get;
set;
}
/// <summary>
/// Gets the length of the underlying stream.
/// </summary>
public virtual long Length
{
get
{
return baseStream.Length;
}
}
/// <summary>
/// Gets or sets the position within the underlying stream.
/// </summary>
public virtual long Position
{
get
{
return baseStream.Position;
}
set
{
baseStream.Position = value;
}
}
/// <summary>
/// Initializes a new data writer for the specified stream.
/// </summary>
public DataWriter(Stream stream, Endianess endianess = Endianess.LittleEndian)
{
this.baseStream = stream;
this.Endianess = endianess;
}
/// <summary>
/// Writes data to the underlying stream. This is the only method that directly accesses
/// the data in the underlying stream.
/// </summary>
protected virtual void WriteToStream(byte[] value, bool ignoreEndianess = false)
{
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
{
var buffer = (byte[])value.Clone();
Array.Reverse(buffer);
baseStream.Write(buffer, 0, buffer.Length);
}
else
{
baseStream.Write(value, 0, value.Length);
}
}
/// <summary>
/// Writes a byte.
/// </summary>
public void Write(byte value)
{
WriteToStream(new byte[] { value });
}
/// <summary>
/// Writes a sequence of bytes.
/// </summary>
public void Write(byte[] value)
{
WriteToStream(value, true);
}
/// <summary>
/// Writes a signed 16-bit value.
/// </summary>
public void Write(short value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a signed 32-bit value.
/// </summary>
public void Write(int value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a signed 64-bit value.
/// </summary>
public void Write(long value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes an unsigned 16-bit value.
/// </summary>
public void Write(ushort value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes an unsigned 32-bit value.
/// </summary>
public void Write(uint value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes an unsigned 64-bit value.
/// </summary>
public void Write(ulong value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a single precision floating point value.
/// </summary>
public void Write(float value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a double precision floating point value.
/// </summary>
public void Write(double value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a string.
/// </summary>
public void Write(string value)
{
foreach (var c in value)
Write((byte)c);
Write((byte)0);
}
public void Write(Vector3 value)
{
Write(value.X);
Write(value.Y);
Write(value.Z);
}
public void Write(Vector4 value)
{
Write(value.X);
Write(value.Y);
Write(value.Z);
Write(value.W);
}
public void Write(Matrix value)
{
Write(value.M11);
Write(value.M21);
Write(value.M31);
Write(value.M41);
Write(value.M12);
Write(value.M22);
Write(value.M32);
Write(value.M42);
Write(value.M13);
Write(value.M23);
Write(value.M33);
Write(value.M43);
Write(value.M14);
Write(value.M24);
Write(value.M34);
Write(value.M44);
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+803
View File
@@ -0,0 +1,803 @@
/*
Copyright(c) 2016 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.
*/
//now with enhanced uglification for codewalker
using SharpDX;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class NavMesh : ResourceFileBase
{
public override long BlockLength
{
get { return 368; }
}
public NavMeshFlags ContentFlags { get; set; }
public uint VersionUnk1 { get; set; } // 0x00010011
public uint Unused_018h { get; set; } // 0x00000000
public uint Unused_01Ch { get; set; } // 0x00000000
public Matrix Transform { get; set; } //(1,0,0,NaN),(0,1,0,NaN),(0,0,1,NaN),(0,0,0,NaN)
public Vector3 AABBSize { get; set; }
public float AABBUnk { get; set; } // 0x7F800001 //NaN
public ulong VerticesPointer { get; set; }
public uint Unused_078h { get; set; } // 0x00000000
public uint Unused_07Ch { get; set; } // 0x00000000
public ulong IndicesPointer { get; set; }
public ulong AdjPolysPointer { get; set; }
public uint AdjPolysIndicesCount { get; set; }
public NavMeshUintArray AdjAreaIDs { get; set; }
public ulong PolysPointer { get; set; }
public ulong SectorTreePointer { get; set; }
public ulong PortalsPointer { get; set; }
public ulong PortalLinksPointer { get; set; }
public uint VerticesCount { get; set; }
public uint PolysCount { get; set; }
public uint AreaID { get; set; } // X + Y*100
public uint TotalBytes { get; set; }
public uint SectorUnkCount { get; set; }
public uint PortalsCount { get; set; }
public uint PortalLinksCount { get; set; }
public uint Unused_154h { get; set; } // 0x00000000
public uint Unused_158h { get; set; } // 0x00000000
public uint Unused_15Ch { get; set; } // 0x00000000
public uint VersionUnk2 { get; set; } //2244687201 (0x85CB3561) for grid ynv's
public uint Unused_164h { get; set; } // 0x00000000
public uint Unused_168h { get; set; } // 0x00000000
public uint Unused_16Ch { get; set; } // 0x00000000
public NavMeshList<NavMeshVertex> Vertices { get; set; }
public NavMeshList<ushort> Indices { get; set; }
public NavMeshList<NavMeshAdjPoly> AdjPolys { get; set; }
public NavMeshList<NavMeshPoly> Polys { get; set; }
public NavMeshSector SectorTree { get; set; }
public NavMeshPortal[] Portals { get; set; }
public ushort[] PortalLinks { get; set; }
private ResourceSystemStructBlock<NavMeshPortal> PortalsBlock = null;
private ResourceSystemStructBlock<ushort> PortalLinksBlock = null;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
ContentFlags = (NavMeshFlags)reader.ReadUInt32();
VersionUnk1 = reader.ReadUInt32();
Unused_018h = reader.ReadUInt32();
Unused_01Ch = reader.ReadUInt32();
Transform = reader.ReadMatrix();
AABBSize = reader.ReadVector3();
AABBUnk = reader.ReadSingle();
VerticesPointer = reader.ReadUInt64();
Unused_078h = reader.ReadUInt32();
Unused_07Ch = reader.ReadUInt32();
IndicesPointer = reader.ReadUInt64();
AdjPolysPointer = reader.ReadUInt64();
AdjPolysIndicesCount = reader.ReadUInt32();
AdjAreaIDs = reader.ReadStruct<NavMeshUintArray>();
PolysPointer = reader.ReadUInt64();
SectorTreePointer = reader.ReadUInt64();
PortalsPointer = reader.ReadUInt64();
PortalLinksPointer = reader.ReadUInt64();
VerticesCount = reader.ReadUInt32();
PolysCount = reader.ReadUInt32();
AreaID = reader.ReadUInt32();
TotalBytes = reader.ReadUInt32();
SectorUnkCount = reader.ReadUInt32();
PortalsCount = reader.ReadUInt32();
PortalLinksCount = reader.ReadUInt32();
Unused_154h = reader.ReadUInt32();
Unused_158h = reader.ReadUInt32();
Unused_15Ch = reader.ReadUInt32();
VersionUnk2 = reader.ReadUInt32();
Unused_164h = reader.ReadUInt32();
Unused_168h = reader.ReadUInt32();
Unused_16Ch = reader.ReadUInt32();
Vertices = reader.ReadBlockAt<NavMeshList<NavMeshVertex>>(VerticesPointer);
Indices = reader.ReadBlockAt<NavMeshList<ushort>>(IndicesPointer);
AdjPolys = reader.ReadBlockAt<NavMeshList<NavMeshAdjPoly>>(AdjPolysPointer);
Polys = reader.ReadBlockAt<NavMeshList<NavMeshPoly>>(PolysPointer);
SectorTree = reader.ReadBlockAt<NavMeshSector>(SectorTreePointer);
Portals = reader.ReadStructsAt<NavMeshPortal>(PortalsPointer, PortalsCount);
PortalLinks = reader.ReadUshortsAt(PortalLinksPointer, PortalLinksCount);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
VerticesPointer = (ulong)(Vertices != null ? Vertices.FilePosition : 0);
IndicesPointer = (ulong)(Indices != null ? Indices.FilePosition : 0);
AdjPolysPointer = (ulong)(AdjPolys != null ? AdjPolys.FilePosition : 0);
PolysPointer = (ulong)(Polys != null ? Polys.FilePosition : 0);
SectorTreePointer = (ulong)(SectorTree != null ? SectorTree.FilePosition : 0);
PortalsPointer = (ulong)(PortalsBlock?.FilePosition ?? 0);
PortalLinksPointer = (ulong)(PortalLinksBlock?.FilePosition ?? 0);
writer.Write((uint)ContentFlags);
writer.Write(VersionUnk1);
writer.Write(Unused_018h);
writer.Write(Unused_01Ch);
writer.Write(Transform);
writer.Write(AABBSize);
writer.Write(AABBUnk);
writer.Write(VerticesPointer);
writer.Write(Unused_078h);
writer.Write(Unused_07Ch);
writer.Write(IndicesPointer);
writer.Write(AdjPolysPointer);
writer.Write(AdjPolysIndicesCount);
writer.WriteStruct(AdjAreaIDs);
writer.Write(PolysPointer);
writer.Write(SectorTreePointer);
writer.Write(PortalsPointer);
writer.Write(PortalLinksPointer);
writer.Write(VerticesCount);
writer.Write(PolysCount);
writer.Write(AreaID);
writer.Write(TotalBytes);
writer.Write(SectorUnkCount);
writer.Write(PortalsCount);
writer.Write(PortalLinksCount);
writer.Write(Unused_154h);
writer.Write(Unused_158h);
writer.Write(Unused_15Ch);
writer.Write(VersionUnk2);
writer.Write(Unused_164h);
writer.Write(Unused_168h);
writer.Write(Unused_16Ch);
}
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>(base.GetReferences());
if (Vertices != null) list.Add(Vertices);
if (Indices != null) list.Add(Indices);
if (AdjPolys != null) list.Add(AdjPolys);
if (Polys != null) list.Add(Polys);
if (SectorTree != null) list.Add(SectorTree);
if ((Portals != null) && (Portals.Length > 0))
{
PortalsBlock = new ResourceSystemStructBlock<NavMeshPortal>(Portals);
list.Add(PortalsBlock);
}
if ((PortalLinks != null) && (PortalLinks.Length > 0))
{
PortalLinksBlock = new ResourceSystemStructBlock<ushort>(PortalLinks);
list.Add(PortalLinksBlock);
}
return list.ToArray();
}
public override string ToString()
{
return "(Size: " + FloatUtil.GetVector3String(AABBSize) + ")";
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshUintArray
{
public uint Count { get; set; }
public uint v00;
public uint v01;
public uint v02;
public uint v03;
public uint v04;
public uint v05;
public uint v06; // 0x00000000
public uint v07; // 0x00000000
public uint v08; // 0x00000000
public uint v09; // 0x00000000
public uint v10; // 0x00000000
public uint v11; // 0x00000000
public uint v12; // 0x00000000
public uint v13; // 0x00000000
public uint v14; // 0x00000000
public uint v15; // 0x00000000
public uint v16; // 0x00000000
public uint v17; // 0x00000000
public uint v18; // 0x00000000
public uint v19; // 0x00000000
public uint v20; // 0x00000000
public uint v21; // 0x00000000
public uint v22; // 0x00000000
public uint v23; // 0x00000000
public uint v24; // 0x00000000
public uint v25; // 0x00000000
public uint v26; // 0x00000000
public uint v27; // 0x00000000
public uint v28; // 0x00000000
public uint v29; // 0x00000000
public uint v30; // 0x00000000
public uint v31; // 0x00000000
public uint[] RawValues
{
get
{
return new[]{ v00,v01,v02,v03,v04,v05,v06,v07,v08,v09,
v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,
v20,v21,v22,v23,v24,v25,v26,v27,v28,v29,
v30,v31 };
}
}
public uint[] Values
{
get
{
uint[] vals = new uint[Count];
uint[] rvals = RawValues;
for (int i = 0; i < Count; i++)
{
vals[i] = rvals[i];
}
return vals;
}
}
public override string ToString()
{
return "(Count: " + Count.ToString() + ")";
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class NavMeshList<T> : ResourceSystemBlock where T : struct
{
public override long BlockLength
{
get { return 48; }
}
public uint VFT { get; set; }
public uint Unknown_04h { get; set; } // 0x00000001
public uint ItemCount { get; set; }
public uint Unknown_0Ch { get; set; } // 0x00000000
public ulong ListPartsPointer { get; set; }
public ulong ListOffsetsPointer { get; set; }
public uint ListPartsCount { get; set; }
public uint Unknown_24h { get; set; } // 0x00000000
public uint Unknown_28h { get; set; } // 0x00000000
public uint Unknown_2Ch { get; set; } // 0x00000000
public ResourceSimpleArray<NavMeshListPart<T>> ListParts { get; set; }
public uint[] ListOffsets { get; set; }
private ResourceSystemStructBlock<uint> ListOffsetsBlock = null;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
VFT = reader.ReadUInt32();
Unknown_04h = reader.ReadUInt32();
ItemCount = reader.ReadUInt32();
Unknown_0Ch = reader.ReadUInt32();
ListPartsPointer = reader.ReadUInt64();
ListOffsetsPointer = reader.ReadUInt64();
ListPartsCount = reader.ReadUInt32();
Unknown_24h = reader.ReadUInt32();
Unknown_28h = reader.ReadUInt32();
Unknown_2Ch = reader.ReadUInt32();
ListParts = reader.ReadBlockAt<ResourceSimpleArray<NavMeshListPart<T>>>(ListPartsPointer, ListPartsCount);
ListOffsets = reader.ReadUintsAt(ListOffsetsPointer, ListPartsCount);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
ListPartsPointer = (ulong)(ListParts != null ? ListParts.FilePosition : 0);
ListOffsetsPointer = (ulong)(ListOffsetsBlock?.FilePosition ?? 0);
ListPartsCount = (uint)(ListParts != null ? ListParts.Count : 0);
writer.Write(VFT);
writer.Write(Unknown_04h);
writer.Write(ItemCount);
writer.Write(Unknown_0Ch);
writer.Write(ListPartsPointer);
writer.Write(ListOffsetsPointer);
writer.Write(ListPartsCount);
writer.Write(Unknown_24h);
writer.Write(Unknown_28h);
writer.Write(Unknown_2Ch);
}
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
if (ListParts != null) list.Add(ListParts);
if ((ListOffsets != null) && (ListOffsets.Length > 0))
{
ListOffsetsBlock = new ResourceSystemStructBlock<uint>(ListOffsets);
list.Add(ListOffsetsBlock);
}
return list.ToArray();
}
public List<T> GetFullList()
{
List<T> list = new List<T>((int)ItemCount);
if (ListParts != null)
{
foreach (var part in ListParts)
{
if (part.Items != null)
{
list.AddRange(part.Items);
}
}
}
return list;
}
public override string ToString()
{
return "(" + ItemCount.ToString() + " total items, " + ListPartsCount.ToString() + " parts)";
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class NavMeshListPart<T> : ResourceSystemBlock where T : struct
{
public override long BlockLength
{
get { return 16; }
}
public ulong Pointer { get; set; }
public uint Count { get; set; }
public uint Unknown_0Ch { get; set; } // 0x00000000
public T[] Items { get; set; }
private ResourceSystemStructBlock<T> ItemsBlock = null;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
Pointer = reader.ReadUInt64();
Count = reader.ReadUInt32();
Unknown_0Ch = reader.ReadUInt32();
Items = reader.ReadStructsAt<T>(Pointer, Count);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
Pointer = (ulong)(ItemsBlock?.FilePosition ?? 0);
Count = (uint)(Items?.Length ?? 0);
writer.Write(Pointer);
writer.Write(Count);
writer.Write(Unknown_0Ch);
}
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
if ((Items != null) && (Items.Length > 0))
{
ItemsBlock = new ResourceSystemStructBlock<T>(Items);
list.Add(ItemsBlock);
}
return list.ToArray();
}
public override string ToString()
{
return "(" + Count.ToString() + " items)";
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshVertex
{
public ushort X { get; set; }
public ushort Y { get; set; }
public ushort Z { get; set; }
public Vector3 ToVector3()
{
const float usmax = (float)ushort.MaxValue;
return new Vector3(X / usmax, Y / usmax, Z / usmax);
}
public override string ToString()
{
return X.ToString() + ", " + Y.ToString() + ", " + Z.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshAABB
{
public short MinX { get; set; }
public short MaxX { get; set; }
public short MinY { get; set; }
public short MaxY { get; set; }
public short MinZ { get; set; }
public short MaxZ { get; set; }
public Vector3 Min { get { return new Vector3(MinX / 4.0f, MinY / 4.0f, MinZ / 4.0f); } }
public Vector3 Max { get { return new Vector3(MaxX / 4.0f, MaxY / 4.0f, MaxZ / 4.0f); } }
public override string ToString()
{
Vector3 min = Min;
Vector3 max = Max;
return string.Format("({0}, {1}, {2}) | ({3}, {4}, {5})", min.X, min.Y, min.Z, max.X, max.Y, max.Z);
//return string.Format("({0}, {1}, {2}) | ({3}, {4}, {5})", MinX, MinY, MinZ, MaxX, MaxY, MaxZ);
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshAdjPoly
{
public NavMeshAdjPolyPart Unknown_0h { get; set; }
public NavMeshAdjPolyPart Unknown_4h { get; set; }
public override string ToString()
{
return Unknown_0h.Bin + " | " + Unknown_4h.Bin + " | " +
Unknown_0h.ToString() + " | " + Unknown_4h.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshAdjPolyPart
{
public uint Value { get; set; }
public string Bin
{
get
{
return Convert.ToString(Value, 2).PadLeft(32, '0');
}
}
public uint AdjAreaIDInd { get { return (Value >> 0) & 0x1F; } }
public uint PolyID { get { return (Value >> 5) & 0x3FFF; } }
public uint Unk2 { get { return (Value >> 19) & 0x3; } }
public uint Unk3 { get { return (Value >> 21); } }
public override string ToString()
{
return AdjAreaIDInd.ToString() + ", " + PolyID.ToString() + ", " + Unk2.ToString() + ", " + Unk3.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshPoly
{
public ushort Unknown_00h { get; set; }
public ushort IndexFlags { get; set; }
public ushort IndexID { get; set; }
public ushort AreaID { get; set; }
public uint Unused_08h { get; set; } // 0x00000000
public uint Unused_0Ch { get; set; } // 0x00000000
public uint Unused_10h { get; set; } // 0x00000000
public uint Unused_14h { get; set; } // 0x00000000
public NavMeshAABB CellAABB { get; set; }
public FlagsUint Unknown_24h { get; set; }
public FlagsUint Unknown_28h { get; set; }
public ushort PartFlags { get; set; }
public ushort PortalID { get; set; }
//public int IndexUnk { get { return (IndexFlags >> 0) & 31; } } //always 0
public int IndexCount { get { return (IndexFlags >> 5); } }
//public int PartUnk1 { get { return (PartFlags >> 0) & 0xF; } } //always 0
public int PartID { get { return (PartFlags >> 4) & 0xFF; } }
public int PartUnk2 { get { return (PartFlags >> 12) & 0xF; } }
public uint Unknown_28h_16 { get { return ((Unknown_28h.Value & 65535)); } }
public uint Unknown_28h_8a { get { return ((Unknown_28h.Value >> 0) & 255); } }
public uint Unknown_28h_8b { get { return ((Unknown_28h.Value >> 8) & 255); } }
public override string ToString()
{
return
//Unknown_28h.Bin + ", (" + Unknown_28h_8a.ToString() + ", " + Unknown_28h_8b.ToString() + "), " +
Unknown_00h.ToString() + ", " +
//IndexFlags.ToString() + ", " +
IndexCount.ToString() + ", " + //IndexUnk.ToString() + ", " +
IndexID.ToString() + ", " + AreaID.ToString() + ", " +
CellAABB.ToString() + ", " +
Unknown_24h.Hex + ", " +
Unknown_28h.Hex + ", " +
//PartFlags.ToString() + ", " + //PartUnk1.ToString() + ", " +
PartID.ToString() + ", " +
PartUnk2.ToString() + ", " +
PortalID.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class NavMeshSector : ResourceSystemBlock
{
public override long BlockLength
{
get { return 96; }
}
public Vector4 AABBMin { get; set; } //W==NaN
public Vector4 AABBMax { get; set; } //W==NaN
public NavMeshAABB CellAABB { get; set; }
public ulong DataPointer { get; set; }
public ulong SubTree1Pointer { get; set; }
public ulong SubTree2Pointer { get; set; }
public ulong SubTree3Pointer { get; set; }
public ulong SubTree4Pointer { get; set; }
public uint Unused_54h { get; set; } // 0x00000000
public uint Unused_58h { get; set; } // 0x00000000
public uint Unused_5Ch { get; set; } // 0x00000000
public NavMeshSectorData Data { get; set; }
public NavMeshSector SubTree1 { get; set; }
public NavMeshSector SubTree2 { get; set; }
public NavMeshSector SubTree3 { get; set; }
public NavMeshSector SubTree4 { get; set; }
public override void Read(ResourceDataReader reader, params object[] parameters)
{
AABBMin = reader.ReadVector4();
AABBMax = reader.ReadVector4();
CellAABB = reader.ReadStruct<NavMeshAABB>();
DataPointer = reader.ReadUInt64();
SubTree1Pointer = reader.ReadUInt64();
SubTree2Pointer = reader.ReadUInt64();
SubTree3Pointer = reader.ReadUInt64();
SubTree4Pointer = reader.ReadUInt64();
Unused_54h = reader.ReadUInt32();
Unused_58h = reader.ReadUInt32();
Unused_5Ch = reader.ReadUInt32();
Data = reader.ReadBlockAt<NavMeshSectorData>(DataPointer);
SubTree1 = reader.ReadBlockAt<NavMeshSector>(SubTree1Pointer);
SubTree2 = reader.ReadBlockAt<NavMeshSector>(SubTree2Pointer);
SubTree3 = reader.ReadBlockAt<NavMeshSector>(SubTree3Pointer);
SubTree4 = reader.ReadBlockAt<NavMeshSector>(SubTree4Pointer);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
DataPointer = (ulong)(Data != null ? Data.FilePosition : 0);
SubTree1Pointer = (ulong)(SubTree1 != null ? SubTree1.FilePosition : 0);
SubTree2Pointer = (ulong)(SubTree2 != null ? SubTree2.FilePosition : 0);
SubTree3Pointer = (ulong)(SubTree3 != null ? SubTree3.FilePosition : 0);
SubTree4Pointer = (ulong)(SubTree4 != null ? SubTree4.FilePosition : 0);
writer.Write(AABBMin);
writer.Write(AABBMax);
writer.WriteStruct(CellAABB);
writer.Write(DataPointer);
writer.Write(SubTree1Pointer);
writer.Write(SubTree2Pointer);
writer.Write(SubTree3Pointer);
writer.Write(SubTree4Pointer);
writer.Write(Unused_54h);
writer.Write(Unused_58h);
writer.Write(Unused_5Ch);
}
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
if (Data != null) list.Add(Data);
if (SubTree1 != null) list.Add(SubTree1);
if (SubTree2 != null) list.Add(SubTree2);
if (SubTree3 != null) list.Add(SubTree3);
if (SubTree4 != null) list.Add(SubTree4);
return list.ToArray();
}
public override string ToString()
{
return "[Min: "+AABBMin.ToString() + "], [Max:" + AABBMax.ToString() + "]";
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class NavMeshSectorData : ResourceSystemBlock
{
public override long BlockLength
{
get { return 32; }
}
public uint UnkOffset { get; set; }
public uint Unused_04h { get; set; } // 0x00000000
public ulong PolyIDsPointer { get; set; }
public ulong UnkDataPointer { get; set; }
public ushort PolyIDsCount { get; set; }
public ushort UnkDataCount { get; set; }
public uint Unused_1Ch { get; set; } // 0x00000000
public ushort[] PolyIDs { get; set; }
public NavMeshSectorDataUnk[] UnkData { get; set; }
private ResourceSystemStructBlock<ushort> PolyIDsBlock = null;
private ResourceSystemStructBlock<NavMeshSectorDataUnk> UnkDataBlock = null;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
UnkOffset = reader.ReadUInt32();
Unused_04h = reader.ReadUInt32();
PolyIDsPointer = reader.ReadUInt64();
UnkDataPointer = reader.ReadUInt64();
PolyIDsCount = reader.ReadUInt16();
UnkDataCount = reader.ReadUInt16();
Unused_1Ch = reader.ReadUInt32();
PolyIDs = reader.ReadUshortsAt(PolyIDsPointer, PolyIDsCount);
UnkData = reader.ReadStructsAt<NavMeshSectorDataUnk>(UnkDataPointer, UnkDataCount);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
PolyIDsPointer = (ulong)(PolyIDsBlock?.FilePosition ?? 0);
PolyIDsCount = (ushort)(PolyIDs?.Length ?? 0);
UnkDataPointer = (ulong)(UnkDataBlock?.FilePosition ?? 0);
UnkDataCount = (ushort)(UnkData?.Length ?? 0);
writer.Write(UnkOffset);
writer.Write(Unused_04h);
writer.Write(PolyIDsPointer);
writer.Write(UnkDataPointer);
writer.Write(PolyIDsCount);
writer.Write(UnkDataCount);
writer.Write(Unused_1Ch);
}
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
if ((PolyIDs != null) && (PolyIDs.Length > 0))
{
PolyIDsBlock = new ResourceSystemStructBlock<ushort>(PolyIDs);
list.Add(PolyIDsBlock);
}
if ((UnkData != null) && (UnkData.Length > 0))
{
UnkDataBlock = new ResourceSystemStructBlock<NavMeshSectorDataUnk>(UnkData);
list.Add(UnkDataBlock);
}
return list.ToArray();
}
public override string ToString()
{
return "(Polys: " + PolyIDsCount.ToString() + ", UnkOffset: " + UnkOffset.ToString() + ", UnkCount: " + UnkDataCount.ToString() + ")";
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshSectorDataUnk
{
public ushort Unknown_0h { get; set; }
public ushort Unknown_2h { get; set; }
public ushort Unknown_4h { get; set; }
public ushort Unknown_6h { get; set; }
public override string ToString()
{
return Unknown_0h.ToString() + ", " + Unknown_2h.ToString() + ", " + Unknown_4h.ToString() + ", " + Unknown_6h.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshPortal
{
public uint Unknown_00h { get; set; }
public NavMeshVertex Position1 { get; set; }
public NavMeshVertex Position2 { get; set; }
public ushort Unknown_10h { get; set; }
public ushort Unknown_12h { get; set; }
public ushort Unknown_14h { get; set; }
public ushort Unknown_16h { get; set; }
public ushort Unknown_18h { get; set; }
public ushort Unknown_1Ah { get; set; }
//public NavMeshAABB AABB1 { get; set; }
//public NavMeshAABB AABB2 { get; set; }
public override string ToString()
{
return Unknown_00h.ToString() + ", " +
Position1.ToString() + ", " + Position2.ToString() + ", " +
Unknown_10h.ToString() + ", " + Unknown_12h.ToString() + ", " +
Unknown_14h.ToString() + ", " + Unknown_16h.ToString() + ", " +
Unknown_18h.ToString() + ", " + Unknown_1Ah.ToString();
//AABB1.ToString() + ", " + AABB2.ToString();
}
}
[Flags] public enum NavMeshFlags : uint
{
Vertices = 1,
Portals = 2,
Vehicle = 4,
Unknown8 = 8,
}
}
+280
View File
@@ -0,0 +1,280 @@
/*
Copyright(c) 2016 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.
*/
//mangled to fit
using SharpDX;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class NodeDictionary : ResourceFileBase
{
public override long BlockLength
{
get { return 112; }
}
public ulong NodesPointer { get; set; }
public uint NodesCount { get; set; }
public uint NodesCountVehicle { get; set; }
public uint NodesCountPed { get; set; }
public uint Unk24 { get; set; } // 0x00000000
public ulong LinksPtr { get; set; }
public uint LinksCount { get; set; }
public uint Unk34 { get; set; } // 0x00000000
public ulong JunctionsPtr { get; set; }
public ulong JunctionHeightmapBytesPtr { get; set; }
public uint Unk48 { get; set; } = 1; // 0x00000001
public uint Unk4C { get; set; } // 0x00000000
public ulong JunctionRefsPtr { get; set; }
public ushort JunctionRefsCount0 { get; set; }
public ushort JunctionRefsCount1 { get; set; } // same as JunctionRefsCount0
public uint Unk5C { get; set; } // 0x00000000
public uint JunctionsCount { get; set; } // same as JunctionRefsCount0
public uint JunctionHeightmapBytesCount { get; set; }
public uint Unk68 { get; set; } // 0x00000000
public uint Unk6C { get; set; } // 0x00000000
public Node[] Nodes { get; set; }
public NodeLink[] Links { get; set; }
public NodeJunction[] Junctions { get; set; }
public byte[] JunctionHeightmapBytes { get; set; }
public NodeJunctionRef[] JunctionRefs { get; set; }
private ResourceSystemStructBlock<Node> NodesBlock = null;
private ResourceSystemStructBlock<NodeLink> LinksBlock = null;
private ResourceSystemStructBlock<NodeJunction> JunctionsBlock = null;
private ResourceSystemStructBlock<byte> JunctionHeightmapBytesBlock = null;
private ResourceSystemStructBlock<NodeJunctionRef> JunctionRefsBlock = null;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
this.NodesPointer = reader.ReadUInt64();
this.NodesCount = reader.ReadUInt32();
this.NodesCountVehicle = reader.ReadUInt32();
this.NodesCountPed = reader.ReadUInt32();
this.Unk24 = reader.ReadUInt32();
this.LinksPtr = reader.ReadUInt64();
this.LinksCount = reader.ReadUInt32();
this.Unk34 = reader.ReadUInt32();
this.JunctionsPtr = reader.ReadUInt64();
this.JunctionHeightmapBytesPtr = reader.ReadUInt64();
this.Unk48 = reader.ReadUInt32();
this.Unk4C = reader.ReadUInt32();
this.JunctionRefsPtr = reader.ReadUInt64();
this.JunctionRefsCount0 = reader.ReadUInt16();
this.JunctionRefsCount1 = reader.ReadUInt16();
this.Unk5C = reader.ReadUInt32();
this.JunctionsCount = reader.ReadUInt32();
this.JunctionHeightmapBytesCount = reader.ReadUInt32();
this.Unk68 = reader.ReadUInt32();
this.Unk6C = reader.ReadUInt32();
this.Nodes = reader.ReadStructsAt<Node>(this.NodesPointer, this.NodesCount);
this.Links = reader.ReadStructsAt<NodeLink>(this.LinksPtr, this.LinksCount);
this.Junctions = reader.ReadStructsAt<NodeJunction>(this.JunctionsPtr, this.JunctionsCount);
this.JunctionHeightmapBytes = reader.ReadBytesAt(this.JunctionHeightmapBytesPtr, this.JunctionHeightmapBytesCount);
this.JunctionRefs = reader.ReadStructsAt<NodeJunctionRef>(this.JunctionRefsPtr, this.JunctionRefsCount1);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
// update structure data
NodesPointer = (ulong)(NodesBlock?.FilePosition ?? 0);
NodesCount = (uint)(Nodes?.Length ?? 0); //assume NodesCountVehicle and Ped already updated..
LinksPtr = (ulong)(LinksBlock?.FilePosition ?? 0);
LinksCount = (uint)(Links?.Length ?? 0);
JunctionsPtr = (ulong)(JunctionsBlock?.FilePosition ?? 0);
JunctionHeightmapBytesPtr = (ulong)(JunctionHeightmapBytesBlock?.FilePosition ?? 0);
JunctionRefsPtr = (ulong)(JunctionRefsBlock?.FilePosition ?? 0);
JunctionRefsCount0 = (ushort)(JunctionRefs?.Length ?? 0);
JunctionRefsCount1 = JunctionRefsCount1;
JunctionsCount = (uint)(Junctions?.Length ?? 0);
JunctionHeightmapBytesCount = (uint)(JunctionHeightmapBytes?.Length ?? 0);
// write structure data
writer.Write(this.NodesPointer);
writer.Write(this.NodesCount);
writer.Write(this.NodesCountVehicle);
writer.Write(this.NodesCountPed);
writer.Write(this.Unk24);
writer.Write(this.LinksPtr);
writer.Write(this.LinksCount);
writer.Write(this.Unk34);
writer.Write(this.JunctionsPtr);
writer.Write(this.JunctionHeightmapBytesPtr);
writer.Write(this.Unk48);
writer.Write(this.Unk4C);
writer.Write(this.JunctionRefsPtr);
writer.Write(this.JunctionRefsCount0);
writer.Write(this.JunctionRefsCount1);
writer.Write(this.Unk5C);
writer.Write(this.JunctionsCount);
writer.Write(this.JunctionHeightmapBytesCount);
writer.Write(this.Unk68);
writer.Write(this.Unk6C);
}
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>(base.GetReferences());
if ((JunctionRefs != null) && (JunctionRefs.Length > 0))
{
JunctionRefsBlock = new ResourceSystemStructBlock<NodeJunctionRef>(JunctionRefs);
list.Add(JunctionRefsBlock);
}
if ((JunctionHeightmapBytes != null) && (JunctionHeightmapBytes.Length > 0))
{
JunctionHeightmapBytesBlock = new ResourceSystemStructBlock<byte>(JunctionHeightmapBytes);
list.Add(JunctionHeightmapBytesBlock);
}
if ((Junctions != null) && (Junctions.Length > 0))
{
JunctionsBlock = new ResourceSystemStructBlock<NodeJunction>(Junctions);
list.Add(JunctionsBlock);
}
if ((Links != null) && (Links.Length > 0))
{
LinksBlock = new ResourceSystemStructBlock<NodeLink>(Links);
list.Add(LinksBlock);
}
if ((Nodes != null) && (Nodes.Length > 0))
{
NodesBlock = new ResourceSystemStructBlock<Node>(Nodes);
list.Add(NodesBlock);
}
return list.ToArray();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct Node
{
public uint Unused0 { get; set; } // 0x00000000
public uint Unused1 { get; set; } // 0x00000000
public uint Unused2 { get; set; } // 0x00000000
public uint Unused3 { get; set; } // 0x00000000
public ushort AreaID { get; set; }
public ushort NodeID { get; set; }
public TextHash StreetName { get; set; }
public ushort Unused4 { get; set; }
public ushort LinkID { get; set; }
public short PositionX { get; set; }
public short PositionY { get; set; }
public FlagsByte Flags0 { get; set; }
public FlagsByte Flags1 { get; set; }
public short PositionZ { get; set; }
public FlagsByte Flags2 { get; set; }
public FlagsByte LinkCountFlags { get; set; }
public FlagsByte Flags3 { get; set; }
public FlagsByte Flags4 { get; set; }
public override string ToString()
{
//return Unused0.ToString() + ", " + Unused1.ToString() + ", " + Unused2.ToString() + ", " +
// Unused3.ToString() + ", " + AreaID.ToString() + ", " + NodeID.ToString() + ", " +
// UnknownInterp.ToString() + ", " + HeuristicCost.ToString() + ", " + LinkID.ToString() + ", " +
// PositionX.ToString() + ", " + PositionY.ToString() + ", " + Unk20.ToString() + ", " + Unk21.ToString() + ", " +
// Unk22.ToString() + ", " + Unk24.ToString() + ", " + Unk26.ToString();
return AreaID.ToString() + ", " + NodeID.ToString() + ", " + StreetName.ToString();// + ", X:" +
//PositionX.ToString() + ", Y:" + PositionY.ToString() + ", " + PositionZ.ToString();// + ", " +
//Flags0.ToString() + ", " + Flags1.ToString() + ", Z:" +
//Flags2.ToString() + ", " + LinkCountFlags.ToString() + ", " +
//Flags3.ToString() + ", " + Flags4.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NodeLink
{
public ushort AreaID { get; set; }
public ushort NodeID { get; set; }
public FlagsByte Flags0 { get; set; }
public FlagsByte Flags1 { get; set; }
public FlagsByte Flags2 { get; set; }
public FlagsByte LinkLength { get; set; }
public override string ToString()
{
return AreaID.ToString() + ", " + NodeID.ToString() + ", " + Flags0.Value.ToString() + ", " + Flags1.Value.ToString() + ", " + Flags2.Value.ToString() + ", " + LinkLength.Value.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NodeJunction
{
public short MaxZ { get; set; }
public short PositionX { get; set; }
public short PositionY { get; set; }
public short MinZ { get; set; }
public ushort HeightmapPtr { get; set; }
public byte HeightmapDimX { get; set; }
public byte HeightmapDimY { get; set; }
public override string ToString()
{
return PositionX.ToString() + ", " + PositionY.ToString() + ": " + MinZ.ToString() + ", " + MaxZ.ToString() + ": " + HeightmapDimX.ToString() + " x " + HeightmapDimY.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NodeJunctionRef
{
public ushort AreaID { get; set; }
public ushort NodeID { get; set; }
public ushort JunctionID { get; set; }
public ushort Unk0 { get; set; }
public override string ToString()
{
return AreaID.ToString() + ", " + NodeID.ToString() + ", " + JunctionID.ToString();
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+340
View File
@@ -0,0 +1,340 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class ResourceBuilder
{
protected const int RESOURCE_IDENT = 0x37435352;
protected const int BASE_SIZE = 0x2000;
private const int SKIP_SIZE = 512;//256;//64;
private const int ALIGN_SIZE = 512;//64;
public static void GetBlocks(IResourceBlock rootBlock, out IList<IResourceBlock> sys, out IList<IResourceBlock> gfx)
{
var systemBlocks = new HashSet<IResourceBlock>();
var graphicBlocks = new HashSet<IResourceBlock>();
var protectedBlocks = new List<IResourceBlock>();
var stack = new Stack<IResourceBlock>();
stack.Push(rootBlock);
var processed = new HashSet<IResourceBlock>();
processed.Add(rootBlock);
while (stack.Count > 0)
{
var block = stack.Pop();
if (block == null)
continue;
if (block is IResourceSystemBlock)
{
if (!systemBlocks.Contains(block))
systemBlocks.Add(block);
// for system blocks, also process references...
var references = ((IResourceSystemBlock)block).GetReferences();
//Array.Reverse(references);
foreach (var reference in references)
if (!processed.Contains(reference))
{
stack.Push(reference);
processed.Add(reference);
}
var subs = new Stack<IResourceSystemBlock>();
foreach (var part in ((IResourceSystemBlock)block).GetParts())
subs.Push((IResourceSystemBlock)part.Item2);
while (subs.Count > 0)
{
var sub = subs.Pop();
foreach (var x in sub.GetReferences())
if (!processed.Contains(x))
{
stack.Push(x);
processed.Add(x);
}
foreach (var x in sub.GetParts())
subs.Push((IResourceSystemBlock)x.Item2);
protectedBlocks.Add(sub);
}
}
else
{
if (!graphicBlocks.Contains(block))
graphicBlocks.Add(block);
}
}
//var result = new List<IResourceBlock>();
//result.AddRange(systemBlocks);
//result.AddRange(graphicBlocks);
//return result;
// there are now sys-blocks in the list that actually
// only substructures and therefore must not get
// a new position!
// -> remove them from the list
foreach (var q in protectedBlocks)
if (systemBlocks.Contains(q))
systemBlocks.Remove(q);
sys = new List<IResourceBlock>();
foreach (var s in systemBlocks)
sys.Add(s);
gfx = new List<IResourceBlock>();
foreach (var s in graphicBlocks)
gfx.Add(s);
}
public static void AssignPositions(IList<IResourceBlock> blocks, uint basePosition, ref int pageSize, out int pageCount)
{
// find largest structure
long largestBlockSize = 0;
foreach (var block in blocks)
{
if (largestBlockSize < block.BlockLength)
largestBlockSize = block.BlockLength;
}
// find minimum page size
long currentPageSize = pageSize;// 0x2000;
while (currentPageSize < largestBlockSize)
currentPageSize *= 2;
long currentPageCount;
long currentPosition;
while (true)
{
currentPageCount = 0;
currentPosition = 0;
// reset all positions
foreach (var block in blocks)
block.FilePosition = -1;
foreach (var block in blocks)
{
if (block.FilePosition != -1)
throw new Exception("A position of -1 is not possible!");
//if (block.Length == 0)
// throw new Exception("A length of 0 is not allowed!");
// check if new page is necessary...
// if yes, add a new page and align to it
long maxSpace = currentPageCount * currentPageSize - currentPosition;
if (maxSpace < (block.BlockLength + SKIP_SIZE))
{
currentPageCount++;
currentPosition = currentPageSize * (currentPageCount - 1);
}
// set position
block.FilePosition = basePosition + currentPosition;
currentPosition += block.BlockLength + SKIP_SIZE;
// align...
if ((currentPosition % ALIGN_SIZE) != 0)
currentPosition += (ALIGN_SIZE - (currentPosition % ALIGN_SIZE));
}
// break if everything fits...
if (currentPageCount < 128)
break;
currentPageSize *= 2;
}
pageSize = (int)currentPageSize;
pageCount = (int)currentPageCount;
}
public static byte[] Build(ResourceFileBase fileBase, int version)
{
fileBase.FilePagesInfo = new ResourcePagesInfo();
IList<IResourceBlock> systemBlocks;
IList<IResourceBlock> graphicBlocks;
GetBlocks(fileBase, out systemBlocks, out graphicBlocks);
int systemPageSize = BASE_SIZE;// *4;
int systemPageCount;
AssignPositions(systemBlocks, 0x50000000, ref systemPageSize, out systemPageCount);
int graphicsPageSize = BASE_SIZE;
int graphicsPageCount;
AssignPositions(graphicBlocks, 0x60000000, ref graphicsPageSize, out graphicsPageCount);
fileBase.FilePagesInfo.SystemPagesCount = 0;
if (systemPageCount > 0)
fileBase.FilePagesInfo.SystemPagesCount = 1; // (byte)systemPageCount; //1
fileBase.FilePagesInfo.GraphicsPagesCount = (byte)graphicsPageCount;
var systemStream = new MemoryStream();
var graphicsStream = new MemoryStream();
var resourceWriter = new ResourceDataWriter(systemStream, graphicsStream);
resourceWriter.Position = 0x50000000;
foreach (var block in systemBlocks)
{
resourceWriter.Position = block.FilePosition;
var pos_before = resourceWriter.Position;
block.Write(resourceWriter);
var pos_after = resourceWriter.Position;
if ((pos_after - pos_before) != block.BlockLength)
{
throw new Exception("error in system length");
}
}
resourceWriter.Position = 0x60000000;
foreach (var block in graphicBlocks)
{
resourceWriter.Position = block.FilePosition;
var pos_before = resourceWriter.Position;
block.Write(resourceWriter);
var pos_after = resourceWriter.Position;
if ((pos_after - pos_before) != block.BlockLength)
{
throw new Exception("error in graphics length");
}
}
var sysDataSize = 0x2000;
while (sysDataSize < systemStream.Length)
{
sysDataSize *= 2;
}
var sysData = new byte[sysDataSize];
systemStream.Flush();
systemStream.Position = 0;
systemStream.Read(sysData, 0, (int)systemStream.Length);
var gfxPageSize = 0x2000;
while (gfxPageSize != graphicsPageSize)
{
gfxPageSize *= 2;
}
var gfxDataSize = graphicsPageCount * gfxPageSize;
var gfxData = new byte[gfxDataSize];
graphicsStream.Flush();
graphicsStream.Position = 0;
graphicsStream.Read(gfxData, 0, (int)graphicsStream.Length);
uint uv = (uint)version;
uint sv = (uv >> 4) & 0xF;
uint gv = (uv >> 0) & 0xF;
//uint sf = RpfResourceFileEntry.GetFlagsFromSize(sysDataSize, sv);
//uint gf = RpfResourceFileEntry.GetFlagsFromSize(gfxDataSize, gv); //TODO: might be broken...
uint sf = RpfResourceFileEntry.GetFlagsFromBlocks((uint)systemPageCount, (uint)systemPageSize, sv);
uint gf = RpfResourceFileEntry.GetFlagsFromBlocks((uint)graphicsPageCount, (uint)graphicsPageSize, gv);
var tdatasize = sysDataSize + gfxDataSize;
var tdata = new byte[tdatasize];
Buffer.BlockCopy(sysData, 0, tdata, 0, sysDataSize);
Buffer.BlockCopy(gfxData, 0, tdata, sysDataSize, gfxDataSize);
var cdata = Compress(tdata);
var dataSize = 16 + cdata.Length;// sysDataSize + gfxDataSize;
var data = new byte[dataSize];
byte[] h1 = BitConverter.GetBytes((uint)0x37435352);
byte[] h2 = BitConverter.GetBytes((int)version);
byte[] h3 = BitConverter.GetBytes(sf);
byte[] h4 = BitConverter.GetBytes(gf);
Buffer.BlockCopy(h1, 0, data, 0, 4);
Buffer.BlockCopy(h2, 0, data, 4, 4);
Buffer.BlockCopy(h3, 0, data, 8, 4);
Buffer.BlockCopy(h4, 0, data, 12, 4);
Buffer.BlockCopy(cdata, 0, data, 16, cdata.Length);
//Buffer.BlockCopy(sysData, 0, data, 16, sysDataSize);
//Buffer.BlockCopy(gfxData, 0, data, 16 + sysDataSize, gfxDataSize);
return data;
}
public static byte[] AddResourceHeader(RpfResourceFileEntry entry, byte[] data)
{
if (data == null) return null;
byte[] newdata = new byte[data.Length + 16];
byte[] h1 = BitConverter.GetBytes((uint)0x37435352);
byte[] h2 = BitConverter.GetBytes(entry.Version);
byte[] h3 = BitConverter.GetBytes(entry.SystemFlags);
byte[] h4 = BitConverter.GetBytes(entry.GraphicsFlags);
Buffer.BlockCopy(h1, 0, newdata, 0, 4);
Buffer.BlockCopy(h2, 0, newdata, 4, 4);
Buffer.BlockCopy(h3, 0, newdata, 8, 4);
Buffer.BlockCopy(h4, 0, newdata, 12, 4);
Buffer.BlockCopy(data, 0, newdata, 16, data.Length);
return newdata;
}
public static byte[] Compress(byte[] data)
{
using (MemoryStream ms = new MemoryStream())
{
DeflateStream ds = new DeflateStream(ms, CompressionMode.Compress, true);
ds.Write(data, 0, data.Length);
ds.Close();
byte[] deflated = ms.GetBuffer();
byte[] outbuf = new byte[ms.Length]; //need to copy to the right size buffer...
Array.Copy(deflated, outbuf, outbuf.Length);
return outbuf;
}
}
public static byte[] Decompress(byte[] data)
{
using (MemoryStream ms = new MemoryStream(data))
{
DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress);
MemoryStream outstr = new MemoryStream();
ds.CopyTo(outstr);
byte[] deflated = outstr.GetBuffer();
byte[] outbuf = new byte[outstr.Length]; //need to copy to the right size buffer...
Array.Copy(deflated, outbuf, outbuf.Length);
return outbuf;
}
}
}
}
+750
View File
@@ -0,0 +1,750 @@
/*
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.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
/// <summary>
/// Represents a resource data reader.
/// </summary>
public class ResourceDataReader : DataReader
{
private const long SYSTEM_BASE = 0x50000000;
private const long GRAPHICS_BASE = 0x60000000;
private Stream systemStream;
private Stream graphicsStream;
// this is a dictionary that contains all the resource blocks
// which were read from this resource reader
private Dictionary<long, List<IResourceBlock>> blockPool;
/// <summary>
/// Gets the length of the underlying stream.
/// </summary>
public override long Length
{
get
{
return -1;
}
}
/// <summary>
/// Gets or sets the position within the underlying stream.
/// </summary>
public override long Position
{
get;
set;
}
/// <summary>
/// Initializes a new resource data reader for the specified system- and graphics-stream.
/// </summary>
public ResourceDataReader(Stream systemStream, Stream graphicsStream, Endianess endianess = Endianess.LittleEndian)
: base((Stream)null, endianess)
{
this.systemStream = systemStream;
this.graphicsStream = graphicsStream;
this.blockPool = new Dictionary<long, List<IResourceBlock>>();
}
public ResourceDataReader(RpfResourceFileEntry resentry, byte[] data, Endianess endianess = Endianess.LittleEndian)
: base((Stream)null, endianess)
{
var systemSize = resentry.SystemSize;
var graphicsSize = resentry.GraphicsSize;
this.systemStream = new MemoryStream(data, 0, systemSize);
this.graphicsStream = new MemoryStream(data, systemSize, graphicsSize);
this.blockPool = new Dictionary<long, List<IResourceBlock>>();
Position = 0x50000000;
}
public ResourceDataReader(int systemSize, int graphicsSize, byte[] data, Endianess endianess = Endianess.LittleEndian)
: base((Stream)null, endianess)
{
this.systemStream = new MemoryStream(data, 0, systemSize);
this.graphicsStream = new MemoryStream(data, systemSize, graphicsSize);
this.blockPool = new Dictionary<long, List<IResourceBlock>>();
Position = 0x50000000;
}
/// <summary>
/// Reads data from the underlying stream. This is the only method that directly accesses
/// the data in the underlying stream.
/// </summary>
protected override byte[] ReadFromStream(int count, bool ignoreEndianess = false)
{
if ((Position & SYSTEM_BASE) == SYSTEM_BASE)
{
// read from system stream...
systemStream.Position = Position & ~0x50000000;
var buffer = new byte[count];
systemStream.Read(buffer, 0, count);
// handle endianess
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
{
Array.Reverse(buffer);
}
Position = systemStream.Position | 0x50000000;
return buffer;
}
if ((Position & GRAPHICS_BASE) == GRAPHICS_BASE)
{
// read from graphic stream...
graphicsStream.Position = Position & ~0x60000000;
var buffer = new byte[count];
graphicsStream.Read(buffer, 0, count);
// handle endianess
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
{
Array.Reverse(buffer);
}
Position = graphicsStream.Position | 0x60000000;
return buffer;
}
throw new Exception("illegal position!");
}
/// <summary>
/// Reads a block.
/// </summary>
public T ReadBlock<T>(params object[] parameters) where T : IResourceBlock, new()
{
// make sure to return the same object if the same
// block is read again...
if (blockPool.ContainsKey(Position))
{
var blocks = blockPool[Position];
foreach (var block in blocks)
if (block is T)
{
Position += block.BlockLength;
// since a resource block of the same type
// has been found at the same address, return it
return (T)block;
}
}
var result = new T();
// replace with correct type...
if (result is IResourceXXSystemBlock)
result = (T)((IResourceXXSystemBlock)result).GetType(this, parameters);
if (result == null)
{
return default(T);
}
// add block to the block pool...
if (blockPool.ContainsKey(Position))
{
blockPool[Position].Add(result);
}
else
{
var blocks = new List<IResourceBlock>();
blocks.Add(result);
blockPool.Add(Position, blocks);
}
var classPosition = Position;
result.Read(this, parameters);
//result.Position = classPosition; //TODO: need this if writing stuff!
return (T)result;
}
/// <summary>
/// Reads a block at a specified position.
/// </summary>
public T ReadBlockAt<T>(ulong position, params object[] parameters) where T : IResourceBlock, new()
{
if (position != 0)
{
var positionBackup = Position;
Position = (long)position;
var result = ReadBlock<T>(parameters);
Position = positionBackup;
return result;
}
else
{
return default(T);
}
}
public byte[] ReadBytesAt(ulong position, uint count)
{
long pos = (long)position;
if ((pos <= 0) || (count == 0)) return null;
var posbackup = Position;
Position = pos;
var result = ReadBytes((int)count);
Position = posbackup;
return result;
}
public ushort[] ReadUshortsAt(ulong position, uint count)
{
if ((position <= 0) || (count == 0)) return null;
var result = new ushort[count];
var length = count * 2;
byte[] data = ReadBytesAt(position, length);
Buffer.BlockCopy(data, 0, result, 0, (int)length);
//var posbackup = Position;
//Position = position;
//var result2 = new ushort[count];
//for (uint i = 0; i < count; i++)
//{
// result2[i] = ReadUInt16();
//}
//Position = posbackup;
return result;
}
public uint[] ReadUintsAt(ulong position, uint count)
{
if ((position <= 0) || (count == 0)) return null;
var result = new uint[count];
var length = count * 4;
byte[] data = ReadBytesAt(position, length);
Buffer.BlockCopy(data, 0, result, 0, (int)length);
//var posbackup = Position;
//Position = position;
//var result = new uint[count];
//for (uint i = 0; i < count; i++)
//{
// result[i] = ReadUInt32();
//}
//Position = posbackup;
return result;
}
public ulong[] ReadUlongsAt(ulong position, uint count)
{
if ((position <= 0) || (count == 0)) return null;
var result = new ulong[count];
var length = count * 8;
byte[] data = ReadBytesAt(position, length);
Buffer.BlockCopy(data, 0, result, 0, (int)length);
//var posbackup = Position;
//Position = position;
//var result = new ulong[count];
//for (uint i = 0; i < count; i++)
//{
// result[i] = ReadUInt64();
//}
//Position = posbackup;
return result;
}
public float[] ReadFloatsAt(ulong position, uint count)
{
if ((position <= 0) || (count == 0)) return null;
var result = new float[count];
var length = count * 4;
byte[] data = ReadBytesAt(position, length);
Buffer.BlockCopy(data, 0, result, 0, (int)length);
//var posbackup = Position;
//Position = position;
//var result = new float[count];
//for (uint i = 0; i < count; i++)
//{
// result[i] = ReadSingle();
//}
//Position = posbackup;
return result;
}
public T[] ReadStructsAt<T>(ulong position, uint count)//, uint structsize)
{
if ((position <= 0) || (count == 0)) return null;
uint structsize = (uint)Marshal.SizeOf(typeof(T));
var length = count * structsize;
byte[] data = ReadBytesAt(position, length);
//var result2 = new T[count];
//Buffer.BlockCopy(data, 0, result2, 0, (int)length); //error: "object must be an array of primitives" :(
var result = new T[count];
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
var h = handle.AddrOfPinnedObject();
for (uint i = 0; i < count; i++)
{
result[i] = Marshal.PtrToStructure<T>(h + (int)(i * structsize));
}
handle.Free();
return result;
}
public T[] ReadStructs<T>(uint count)
{
uint structsize = (uint)Marshal.SizeOf(typeof(T));
var result = new T[count];
var length = count * structsize;
byte[] data = ReadBytes((int)length);
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
var h = handle.AddrOfPinnedObject();
for (uint i = 0; i < count; i++)
{
result[i] = Marshal.PtrToStructure<T>(h + (int)(i * structsize));
}
handle.Free();
return result;
}
public T ReadStruct<T>() where T : struct
{
uint structsize = (uint)Marshal.SizeOf(typeof(T));
var length = structsize;
byte[] data = ReadBytes((int)length);
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
var h = handle.AddrOfPinnedObject();
var result = Marshal.PtrToStructure<T>(h);
handle.Free();
return result;
}
public T ReadStructAt<T>(long position) where T : struct
{
if ((position <= 0)) return default(T);
var posbackup = Position;
Position = (long)position;
var result = ReadStruct<T>();
Position = posbackup;
return result;
}
public string ReadStringAt(ulong position)
{
long newpos = (long)position;
if ((newpos <= 0)) return null;
var lastpos = Position;
Position = newpos;
var result = ReadString();
Position = lastpos;
return result;
}
}
/// <summary>
/// Represents a resource data writer.
/// </summary>
public class ResourceDataWriter : DataWriter
{
private const long SYSTEM_BASE = 0x50000000;
private const long GRAPHICS_BASE = 0x60000000;
private Stream systemStream;
private Stream graphicsStream;
/// <summary>
/// Gets the length of the underlying stream.
/// </summary>
public override long Length
{
get
{
return -1;
}
}
/// <summary>
/// Gets or sets the position within the underlying stream.
/// </summary>
public override long Position
{
get;
set;
}
/// <summary>
/// Initializes a new resource data reader for the specified system- and graphics-stream.
/// </summary>
public ResourceDataWriter(Stream systemStream, Stream graphicsStream, Endianess endianess = Endianess.LittleEndian)
: base((Stream)null, endianess)
{
this.systemStream = systemStream;
this.graphicsStream = graphicsStream;
}
/// <summary>
/// Writes data to the underlying stream. This is the only method that directly accesses
/// the data in the underlying stream.
/// </summary>
protected override void WriteToStream(byte[] value, bool ignoreEndianess = true)
{
if ((Position & SYSTEM_BASE) == SYSTEM_BASE)
{
// write to system stream...
systemStream.Position = Position & ~SYSTEM_BASE;
// handle endianess
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
{
var buf = (byte[])value.Clone();
Array.Reverse(buf);
systemStream.Write(buf, 0, buf.Length);
}
else
{
systemStream.Write(value, 0, value.Length);
}
Position = systemStream.Position | 0x50000000;
return;
}
if ((Position & GRAPHICS_BASE) == GRAPHICS_BASE)
{
// write to graphic stream...
graphicsStream.Position = Position & ~GRAPHICS_BASE;
// handle endianess
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
{
var buf = (byte[])value.Clone();
Array.Reverse(buf);
graphicsStream.Write(buf, 0, buf.Length);
}
else
{
graphicsStream.Write(value, 0, value.Length);
}
Position = graphicsStream.Position | 0x60000000;
return;
}
throw new Exception("illegal position!");
}
/// <summary>
/// Writes a block.
/// </summary>
public void WriteBlock(IResourceBlock value)
{
value.Write(this);
}
public void WriteStruct<T>(T val) where T : struct
{
int size = Marshal.SizeOf(typeof(T));
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(val, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
Write(arr);
}
}
/// <summary>
/// Represents a data block in a resource file.
/// </summary>
public interface IResourceBlock
{
/// <summary>
/// Gets or sets the position of the data block.
/// </summary>
long FilePosition { get; set; }
/// <summary>
/// Gets the length of the data block.
/// </summary>
long BlockLength { get; }
/// <summary>
/// Reads the data block.
/// </summary>
void Read(ResourceDataReader reader, params object[] parameters);
/// <summary>
/// Writes the data block.
/// </summary>
void Write(ResourceDataWriter writer, params object[] parameters);
}
/// <summary>
/// Represents a data block of the system segement in a resource file.
/// </summary>
public interface IResourceSystemBlock : IResourceBlock
{
/// <summary>
/// Returns a list of data blocks that are part of this block.
/// </summary>
Tuple<long, IResourceBlock>[] GetParts();
/// <summary>
/// Returns a list of data blocks that are referenced by this block.
/// </summary>
IResourceBlock[] GetReferences();
}
public interface IResourceXXSystemBlock : IResourceSystemBlock
{
IResourceSystemBlock GetType(ResourceDataReader reader, params object[] parameters);
}
/// <summary>
/// Represents a data block of the graphics segmenet in a resource file.
/// </summary>
public interface IResourceGraphicsBlock : IResourceBlock
{ }
/// <summary>
/// Represents a data block of the system segement in a resource file.
/// </summary>
[TypeConverter(typeof(ExpandableObjectConverter))] public abstract class ResourceSystemBlock : IResourceSystemBlock
{
private long position;
/// <summary>
/// Gets or sets the position of the data block.
/// </summary>
public virtual long FilePosition
{
get
{
return position;
}
set
{
position = value;
foreach (var part in GetParts())
{
part.Item2.FilePosition = value + part.Item1;
}
}
}
/// <summary>
/// Gets the length of the data block.
/// </summary>
public abstract long BlockLength
{
get;
}
/// <summary>
/// Reads the data block.
/// </summary>
public abstract void Read(ResourceDataReader reader, params object[] parameters);
/// <summary>
/// Writes the data block.
/// </summary>
public abstract void Write(ResourceDataWriter writer, params object[] parameters);
/// <summary>
/// Returns a list of data blocks that are part of this block.
/// </summary>
public virtual Tuple<long, IResourceBlock>[] GetParts()
{
return new Tuple<long, IResourceBlock>[0];
}
/// <summary>
/// Returns a list of data blocks that are referenced by this block.
/// </summary>
public virtual IResourceBlock[] GetReferences()
{
return new IResourceBlock[0];
}
}
public abstract class ResourecTypedSystemBlock : ResourceSystemBlock, IResourceXXSystemBlock
{
public abstract IResourceSystemBlock GetType(ResourceDataReader reader, params object[] parameters);
}
/// <summary>
/// Represents a data block of the graphics segmenet in a resource file.
/// </summary>
public abstract class ResourceGraphicsBlock : IResourceGraphicsBlock
{
/// <summary>
/// Gets or sets the position of the data block.
/// </summary>
public virtual long FilePosition
{
get;
set;
}
/// <summary>
/// Gets the length of the data block.
/// </summary>
public abstract long BlockLength
{
get;
}
/// <summary>
/// Reads the data block.
/// </summary>
public abstract void Read(ResourceDataReader reader, params object[] parameters);
/// <summary>
/// Writes the data block.
/// </summary>
public abstract void Write(ResourceDataWriter writer, params object[] parameters);
}
public class ResourceSystemDataBlock : ResourceSystemBlock //used for writing resources.
{
public byte[] Data { get; set; }
public int DataLength { get; set; }
public override long BlockLength
{
get
{
return (Data != null) ? Data.Length : DataLength;
}
}
public ResourceSystemDataBlock(byte[] data)
{
Data = data;
DataLength = (Data != null) ? Data.Length : 0;
}
public override void Read(ResourceDataReader reader, params object[] parameters)
{
Data = reader.ReadBytes(DataLength);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
writer.Write(Data);
}
}
public class ResourceSystemStructBlock<T> : ResourceSystemBlock where T : struct //used for writing resources.
{
public T[] Items { get; set; }
public int ItemCount { get; set; }
public int StructureSize { get; set; }
public override long BlockLength
{
get
{
return ((Items != null) ? Items.Length : ItemCount) * StructureSize;
}
}
public ResourceSystemStructBlock(T[] items)
{
Items = items;
ItemCount = (Items != null) ? Items.Length : 0;
StructureSize = Marshal.SizeOf(typeof(T));
}
public override void Read(ResourceDataReader reader, params object[] parameters)
{
int datalength = ItemCount * StructureSize;
byte[] data = reader.ReadBytes(datalength);
Items = MetaTypes.ConvertDataArray<T>(data, 0, ItemCount);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
byte[] data = MetaTypes.ConvertArrayToBytes(Items);
writer.Write(data);
}
}
//public interface ResourceDataStruct
//{
// void Read(ResourceDataReader reader);
// void Write(ResourceDataWriter writer);
//}
}
+149
View File
@@ -0,0 +1,149 @@
/*
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 SharpDX;
using SharpDX.DXGI;
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 ResourceFileBase : ResourceSystemBlock
{
public override long BlockLength
{
get { return 16; }
}
// structure data
public uint FileVFT { get; set; }
public uint FileUnknown { get; set; }
public ulong FilePagesInfoPointer { get; set; }
// reference data
public ResourcePagesInfo FilePagesInfo { get; set; }
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.FileVFT = reader.ReadUInt32();
this.FileUnknown = reader.ReadUInt32();
this.FilePagesInfoPointer = reader.ReadUInt64();
// read reference data
this.FilePagesInfo = reader.ReadBlockAt<ResourcePagesInfo>(
this.FilePagesInfoPointer // offset
);
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
// update structure data
this.FilePagesInfoPointer = (ulong)(this.FilePagesInfo != null ? this.FilePagesInfo.FilePosition : 0);
// write structure data
writer.Write(this.FileVFT);
writer.Write(this.FileUnknown);
writer.Write(this.FilePagesInfoPointer);
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
if (FilePagesInfo != null) list.Add(FilePagesInfo);
return list.ToArray();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class ResourcePagesInfo : ResourceSystemBlock
{
public override long BlockLength
{
get { return 20; }
}
// structure data
public uint Unknown_0h { get; set; }
public uint Unknown_4h { get; set; }
public byte SystemPagesCount { get; set; }
public byte GraphicsPagesCount { get; set; }
public ushort Unknown_Ah { get; set; }
public uint Unknown_Ch { get; set; }
public uint Unknown_10h { get; set; }
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.Unknown_0h = reader.ReadUInt32();
this.Unknown_4h = reader.ReadUInt32();
this.SystemPagesCount = reader.ReadByte();
this.GraphicsPagesCount = reader.ReadByte();
this.Unknown_Ah = reader.ReadUInt16();
this.Unknown_Ch = reader.ReadUInt32();
this.Unknown_10h = reader.ReadUInt32();
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
// write structure data
writer.Write(this.Unknown_0h);
writer.Write(this.Unknown_4h);
writer.Write(this.SystemPagesCount);
writer.Write(this.GraphicsPagesCount);
writer.Write(this.Unknown_Ah);
writer.Write(this.Unknown_Ch);
writer.Write(this.Unknown_10h);
}
public override string ToString()
{
return SystemPagesCount.ToString() + ", " + GraphicsPagesCount.ToString();
}
}
}
File diff suppressed because it is too large Load Diff
+423
View File
@@ -0,0 +1,423 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker.GameFiles
{
public class RpfManager
{
//for caching and management of RPF file data.
public string Folder { get; private set; }
public string[] ExcludePaths { get; set; }
public bool EnableMods { get; set; }
public Action<string> UpdateStatus { get; private set; }
public Action<string> ErrorLog { get; private set; }
public List<RpfFile> BaseRpfs { get; private set; }
public List<RpfFile> ModRpfs { get; private set; }
public List<RpfFile> DlcRpfs { get; private set; }
public List<RpfFile> AllRpfs { get; private set; }
public List<RpfFile> DlcNoModRpfs { get; private set; }
public List<RpfFile> AllNoModRpfs { get; private set; }
public Dictionary<string, RpfFile> RpfDict { get; private set; }
public Dictionary<string, RpfEntry> EntryDict { get; private set; }
public Dictionary<string, RpfFile> ModRpfDict { get; private set; }
public Dictionary<string, RpfEntry> ModEntryDict { get; private set; }
public volatile bool IsInited = false;
public void Init(string folder, Action<string> updateStatus, Action<string> errorLog, bool rootOnly = false)
{
UpdateStatus = updateStatus;
ErrorLog = errorLog;
string replpath = folder + "\\";
var sopt = rootOnly ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories;
string[] allfiles = Directory.GetFiles(folder, "*.rpf", sopt);
BaseRpfs = new List<RpfFile>();
ModRpfs = new List<RpfFile>();
DlcRpfs = new List<RpfFile>();
AllRpfs = new List<RpfFile>();
DlcNoModRpfs = new List<RpfFile>();
AllNoModRpfs = new List<RpfFile>();
RpfDict = new Dictionary<string, RpfFile>();
EntryDict = new Dictionary<string, RpfEntry>();
ModRpfDict = new Dictionary<string, RpfFile>();
ModEntryDict = new Dictionary<string, RpfEntry>();
foreach (string rpfpath in allfiles)
{
try
{
RpfFile rf = new RpfFile(rpfpath, rpfpath.Replace(replpath, ""));
if (ExcludePaths != null)
{
bool excl = false;
for (int i = 0; i < ExcludePaths.Length; i++)
{
if (rf.Path.StartsWith(ExcludePaths[i]))
{
excl = true;
break;
}
}
if (excl) continue; //skip files in exclude paths.
}
rf.ScanStructure(updateStatus, errorLog);
AddRpfFile(rf, false, false);
}
catch (Exception ex)
{
errorLog(rpfpath + ": " + ex.ToString());
}
}
updateStatus("Building jenkindex...");
BuildBaseJenkIndex();
updateStatus("Scan complete");
IsInited = true;
}
public void Init(List<RpfFile> allRpfs)
{
//fast init used by RPF explorer's File cache
AllRpfs = allRpfs;
BaseRpfs = new List<RpfFile>();
ModRpfs = new List<RpfFile>();
DlcRpfs = new List<RpfFile>();
DlcNoModRpfs = new List<RpfFile>();
AllNoModRpfs = new List<RpfFile>();
RpfDict = new Dictionary<string, RpfFile>();
EntryDict = new Dictionary<string, RpfEntry>();
ModRpfDict = new Dictionary<string, RpfFile>();
ModEntryDict = new Dictionary<string, RpfEntry>();
foreach (var rpf in allRpfs)
{
RpfDict[rpf.Path] = rpf;
if (rpf.AllEntries == null) continue;
foreach (var entry in rpf.AllEntries)
{
EntryDict[entry.Path] = entry;
}
}
IsInited = true;
}
private void AddRpfFile(RpfFile file, bool isdlc, bool ismod)
{
isdlc = isdlc || (file.NameLower == "dlc.rpf") || (file.NameLower == "update.rpf");
ismod = ismod || (file.Path.StartsWith("mods\\"));
if (file.AllEntries != null)
{
AllRpfs.Add(file);
if (!ismod)
{
AllNoModRpfs.Add(file);
}
if (isdlc)
{
DlcRpfs.Add(file);
if (!ismod)
{
DlcNoModRpfs.Add(file);
}
}
else
{
if (ismod)
{
ModRpfs.Add(file);
}
else
{
BaseRpfs.Add(file);
}
}
if (ismod)
{
ModRpfDict[file.Path.Substring(5)] = file;
}
RpfDict[file.Path] = file;
foreach (RpfEntry entry in file.AllEntries)
{
try
{
if (!string.IsNullOrEmpty(entry.Name))
{
if (ismod)
{
ModEntryDict[entry.Path] = entry;
ModEntryDict[entry.Path.Substring(5)] = entry;
}
else
{
EntryDict[entry.Path] = entry;
}
if (entry is RpfFileEntry)
{
RpfFileEntry fentry = entry as RpfFileEntry;
entry.NameHash = JenkHash.GenHash(entry.NameLower);
int ind = entry.NameLower.LastIndexOf('.');
entry.ShortNameHash = (ind > 0) ? JenkHash.GenHash(entry.NameLower.Substring(0, ind)) : entry.NameHash;
if (entry.ShortNameHash != 0)
{
//EntryHashDict[entry.ShortNameHash] = entry;
}
}
}
}
catch (Exception ex)
{
file.LastError = ex.ToString();
file.LastException = ex;
ErrorLog(entry.Path + ": " + ex.ToString());
}
}
}
if (file.Children != null)
{
foreach (RpfFile cfile in file.Children)
{
AddRpfFile(cfile, isdlc, ismod);
}
}
}
public RpfFile FindRpfFile(string path)
{
RpfFile file = null; //check the dictionary
if (EnableMods && ModRpfDict.TryGetValue(path, out file))
{
return file;
}
if (RpfDict.TryGetValue(path, out file))
{
return file;
}
string lpath = path.ToLower(); //try look at names etc
foreach (RpfFile tfile in AllRpfs)
{
if (tfile.NameLower == lpath)
{
return tfile;
}
if (tfile.Path == lpath)
{
return tfile;
}
}
return file;
}
public RpfEntry GetEntry(string path)
{
RpfEntry entry;
string pathl = path.ToLower();
if (EnableMods && ModEntryDict.TryGetValue(pathl, out entry))
{
return entry;
}
EntryDict.TryGetValue(pathl, out entry);
if (entry == null)
{
pathl = pathl.Replace("/", "\\");
pathl = pathl.Replace("common:", "common.rpf");
if (EnableMods && ModEntryDict.TryGetValue(pathl, out entry))
{
return entry;
}
EntryDict.TryGetValue(pathl, out entry);
}
return entry;
}
public byte[] GetFileData(string path)
{
byte[] data = null;
RpfFileEntry entry = GetEntry(path) as RpfFileEntry;
if (entry != null)
{
data = entry.File.ExtractFile(entry);
}
return data;
}
public string GetFileUTF8Text(string path)
{
byte[] bytes = GetFileData(path);
if (bytes == null)
{ return string.Empty; } //file not found..
if ((bytes.Length > 3) && (bytes[0] == 0xEF) && (bytes[1] == 0xBB) && (bytes[2] == 0xBF))
{
byte[] newb = new byte[bytes.Length - 3];
for (int i = 3; i < bytes.Length; i++)
{
newb[i - 3] = bytes[i];
}
bytes = newb; //trim starting 3 "magic" bytes?
}
return Encoding.UTF8.GetString(bytes);
}
public XmlDocument GetFileXml(string path)
{
XmlDocument doc = new XmlDocument();
string text = GetFileUTF8Text(path);
if (!string.IsNullOrEmpty(text))
{
doc.LoadXml(text);
}
return doc;
}
public T GetFile<T>(string path) where T : class, PackedFile, new()
{
T file = null;
byte[] data = null;
RpfFileEntry entry = GetEntry(path) as RpfFileEntry;
if (entry != null)
{
data = entry.File.ExtractFile(entry);
}
if (data != null)
{
file = new T();
file.Load(data, entry);
}
return file;
}
public T GetFile<T>(RpfEntry e) where T : class, PackedFile, new()
{
T file = null;
byte[] data = null;
RpfFileEntry entry = e as RpfFileEntry;
if (entry != null)
{
data = entry.File.ExtractFile(entry);
}
if (data != null)
{
file = new T();
file.Load(data, entry);
}
return file;
}
public bool LoadFile<T>(T file, RpfEntry e) where T : class, PackedFile
{
byte[] data = null;
RpfFileEntry entry = e as RpfFileEntry;
if (entry != null)
{
data = entry.File.ExtractFile(entry);
}
if (data != null)
{
file.Load(data, entry);
return true;
}
return false;
}
public void BuildBaseJenkIndex()
{
JenkIndex.Clear();
foreach (RpfFile file in AllRpfs)
{
try
{
JenkIndex.Ensure(file.Name);
foreach (RpfEntry entry in file.AllEntries)
{
var nlow = entry.NameLower;
if (string.IsNullOrEmpty(nlow)) continue;
JenkIndex.Ensure(entry.Name);
JenkIndex.Ensure(nlow);
//JenkIndex.Ensure(entry.Path);
//JenkIndex.Ensure(entry.Path.ToLower());
int ind = nlow.LastIndexOf('.');
if (ind > 0)
{
JenkIndex.Ensure(entry.Name.Substring(0, ind));
JenkIndex.Ensure(nlow.Substring(0, ind));
//if (ind < entry.Name.Length - 2)
//{
// JenkIndex.Ensure(entry.Name.Substring(0, ind) + ".#" + entry.Name.Substring(ind + 2));
// JenkIndex.Ensure(entry.NameLower.Substring(0, ind) + ".#" + entry.NameLower.Substring(ind + 2));
//}
}
if (nlow.EndsWith(".ydr") || nlow.EndsWith(".yft"))
{
var sname = nlow.Substring(0, nlow.Length - 4);
JenkIndex.Ensure(sname + "_lod");
JenkIndex.Ensure(sname + "_loda");
JenkIndex.Ensure(sname + "_lodb");
}
if (nlow.EndsWith(".ydd"))
{
if (nlow.EndsWith("_children.ydd"))
{
var strn = nlow.Substring(0, nlow.Length - 13);
JenkIndex.Ensure(strn);
JenkIndex.Ensure(strn + "_lod");
JenkIndex.Ensure(strn + "_loda");
JenkIndex.Ensure(strn + "_lodb");
}
var idx = nlow.LastIndexOf('_');
if (idx > 0)
{
var str1 = nlow.Substring(0, idx);
var idx2 = str1.LastIndexOf('_');
if (idx2 > 0)
{
var str2 = str1.Substring(0, idx2);
JenkIndex.Ensure(str2 + "_lod");
var maxi = 100;
for (int i = 1; i <= maxi; i++)
{
var str3 = str2 + "_" + i.ToString().PadLeft(2, '0');
//JenkIndex.Ensure(str3);
JenkIndex.Ensure(str3 + "_lod");
}
}
}
}
}
}
catch
{
//failing silently!! not so good really
}
}
}
}
}
+591
View File
@@ -0,0 +1,591 @@
using SharpDX.DXGI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class TextureDictionary : ResourceFileBase
{
public override long BlockLength
{
get
{
return 64;
}
}
// structure data
public uint Unknown_10h { get; set; } // 0x00000000
public uint Unknown_14h { get; set; } // 0x00000000
public uint Unknown_18h { get; set; } // 0x00000001
public uint Unknown_1Ch { get; set; } // 0x00000000
public ResourceSimpleList64Ptr TextureNameHashesPtr { get; set; }
public uint[] TextureNameHashes { get; set; }
public ResourcePointerList64<Texture> Textures { get; set; }
public Dictionary<uint, Texture> Dict { get; set; }
public long MemoryUsage
{
get
{
long val = 0;
if ((Textures != null) && (Textures.data_items != null))
{
foreach (var tex in Textures.data_items)
{
if (tex != null)
{
val += tex.MemoryUsage;
}
}
}
return val;
}
}
public TextureDictionary()
{
//this.TextureNameHashes = new ResourceSimpleList64<uint_r>();
this.Textures = new ResourcePointerList64<Texture>();
}
/// <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.ReadUInt32();
this.Unknown_14h = reader.ReadUInt32();
this.Unknown_18h = reader.ReadUInt32();
this.Unknown_1Ch = reader.ReadUInt32();
this.TextureNameHashesPtr = reader.ReadStruct<ResourceSimpleList64Ptr>();
this.TextureNameHashes = reader.ReadUintsAt(this.TextureNameHashesPtr.EntriesPointer, this.TextureNameHashesPtr.EntriesCount);
//this.TextureNameHashes = reader.ReadBlock<ResourceSimpleList64<uint_r>>();
this.Textures = reader.ReadBlock<ResourcePointerList64<Texture>>();
var dict = new Dictionary<uint, Texture>();
if ((Textures != null) && (Textures.data_items != null) && (TextureNameHashes != null))
{
for (int i = 0; (i < Textures.data_items.Length) && (i < TextureNameHashes.Length); i++)
{
var tex = Textures.data_items[i];
var hash = TextureNameHashes[i];
dict[hash] = tex;
}
}
Dict = new Dictionary<uint, Texture>(dict);
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
// write structure data
writer.Write(this.Unknown_10h);
writer.Write(this.Unknown_14h);
writer.Write(this.Unknown_18h);
writer.Write(this.Unknown_1Ch);
//writer.WriteBlock(this.TextureNameHashes); //TODO: fix!
//writer.WriteBlock(this.Textures);
}
public override Tuple<long, IResourceBlock>[] GetParts()
{
return new Tuple<long, IResourceBlock>[] {
//new Tuple<long, IResourceBlock>(0x20, TextureNameHashes), //TODO: fix!
new Tuple<long, IResourceBlock>(0x30, Textures)
};
}
public Dictionary<uint, Texture> GetDictionary()
{
Dictionary<uint, Texture> td = new Dictionary<uint, Texture>();
if ((Textures != null) && (Textures.data_items != null))
{
var texs = Textures.data_items;
var hashes = TextureNameHashes;
for (int i = 0; (i < texs.Length) && (i < hashes.Length); i++)
{
td.Add(hashes[i], texs[i]);
}
}
return td;
}
public Texture Lookup(uint hash)
{
Texture tex = null;
if (Dict != null)
{
Dict.TryGetValue(hash, out tex);
}
return tex;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class TextureBase : ResourceSystemBlock
{
public override long BlockLength
{
get { return 64; }
}
// structure data
public uint VFT { get; set; }
public uint Unknown_4h { get; set; } // 0x00000001
public uint Unknown_8h { get; set; } // 0x00000000
public uint Unknown_Ch { get; set; } // 0x00000000
public uint Unknown_10h { get; set; } // 0x00000000
public uint Unknown_14h { get; set; } // 0x00000000
public uint Unknown_18h { get; set; } // 0x00000000
public uint Unknown_1Ch { get; set; } // 0x00000000
public uint Unknown_20h { get; set; } // 0x00000000
public uint Unknown_24h { get; set; } // 0x00000000
public ulong NamePointer { get; set; }
public uint Unknown_30h { get; set; }
public uint Unknown_34h { get; set; } // 0x00000000
public uint Unknown_38h { get; set; } // 0x00000000
public uint Unknown_3Ch { get; set; } // 0x00000000
// reference data
public string Name { get; set; }
public uint NameHash { get; set; }
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.VFT = reader.ReadUInt32();
this.Unknown_4h = reader.ReadUInt32();
this.Unknown_8h = reader.ReadUInt32();
this.Unknown_Ch = reader.ReadUInt32();
this.Unknown_10h = reader.ReadUInt32();
this.Unknown_14h = reader.ReadUInt32();
this.Unknown_18h = reader.ReadUInt32();
this.Unknown_1Ch = reader.ReadUInt32();
this.Unknown_20h = reader.ReadUInt32();
this.Unknown_24h = reader.ReadUInt32();
this.NamePointer = reader.ReadUInt64();
this.Unknown_30h = reader.ReadUInt32();
this.Unknown_34h = reader.ReadUInt32();
this.Unknown_38h = reader.ReadUInt32();
this.Unknown_3Ch = reader.ReadUInt32();
// read reference data
this.Name = reader.ReadStringAt( //BlockAt<string_r>(
this.NamePointer // offset
);
if (!string.IsNullOrEmpty(Name))
{
NameHash = JenkHash.GenHash(Name.ToLower());
}
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
// update structure data
//this.NamePointer = (ulong)(this.Name != null ? this.Name.Position : 0); //TODO: fix
// write structure data
writer.Write(this.VFT);
writer.Write(this.Unknown_4h);
writer.Write(this.Unknown_8h);
writer.Write(this.Unknown_Ch);
writer.Write(this.Unknown_10h);
writer.Write(this.Unknown_14h);
writer.Write(this.Unknown_18h);
writer.Write(this.Unknown_1Ch);
writer.Write(this.Unknown_20h);
writer.Write(this.Unknown_24h);
writer.Write(this.NamePointer);
writer.Write(this.Unknown_30h);
writer.Write(this.Unknown_34h);
writer.Write(this.Unknown_38h);
writer.Write(this.Unknown_3Ch);
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
//if (Name != null) list.Add(Name); //TODO: fix
return list.ToArray();
}
public override string ToString()
{
return "TextureBase: " + Name;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class Texture : TextureBase
{
public override long BlockLength
{
get { return 144; }
}
// structure data
public uint Unknown_40h { get; set; }
public uint Unknown_44h { get; set; } // 0x00000000
public uint Unknown_48h { get; set; }
public uint Unknown_4Ch { get; set; } // 0x00000000
public ushort Width { get; set; }
public ushort Height { get; set; }
public ushort Unknown_54h { get; set; } // 0x0001
public ushort Stride { get; set; }
public TextureFormat Format { get; set; }
public byte Unknown_5Ch { get; set; } // 0x00
public byte Levels { get; set; }
public ushort Unknown_5Eh { get; set; } // 0x0000
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
public ulong DataPointer { get; set; }
public uint Unknown_78h { get; set; } // 0x00000000
public uint Unknown_7Ch { get; set; } // 0x00000000
public uint Unknown_80h { get; set; } // 0x00000000
public uint Unknown_84h { get; set; } // 0x00000000
public uint Unknown_88h { get; set; } // 0x00000000
public uint Unknown_8Ch { get; set; } // 0x00000000
// reference data
public TextureData Data { get; set; }
public long MemoryUsage
{
get
{
long val = 0;
if (Data != null)
{
val += Data.FullData.LongLength;
}
return val;
}
}
/// <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_40h = reader.ReadUInt32();
this.Unknown_44h = reader.ReadUInt32();
this.Unknown_48h = reader.ReadUInt32();
this.Unknown_4Ch = reader.ReadUInt32();
this.Width = reader.ReadUInt16();
this.Height = reader.ReadUInt16();
this.Unknown_54h = reader.ReadUInt16();
this.Stride = reader.ReadUInt16();
this.Format = (TextureFormat)reader.ReadUInt32();
this.Unknown_5Ch = reader.ReadByte();
this.Levels = reader.ReadByte();
this.Unknown_5Eh = reader.ReadUInt16();
this.Unknown_60h = reader.ReadUInt32();
this.Unknown_64h = reader.ReadUInt32();
this.Unknown_68h = reader.ReadUInt32();
this.Unknown_6Ch = reader.ReadUInt32();
this.DataPointer = reader.ReadUInt64();
this.Unknown_78h = reader.ReadUInt32();
this.Unknown_7Ch = reader.ReadUInt32();
this.Unknown_80h = reader.ReadUInt32();
this.Unknown_84h = reader.ReadUInt32();
this.Unknown_88h = reader.ReadUInt32();
this.Unknown_8Ch = reader.ReadUInt32();
// read reference data
this.Data = reader.ReadBlockAt<TextureData>(
this.DataPointer, // offset
this.Format,
this.Width,
this.Height,
this.Levels,
this.Stride
);
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
this.DataPointer = (ulong)this.Data.FilePosition;
// write structure data
writer.Write(this.Unknown_40h);
writer.Write(this.Unknown_44h);
writer.Write(this.Unknown_48h);
writer.Write(this.Unknown_4Ch);
writer.Write(this.Width);
writer.Write(this.Height);
writer.Write(this.Unknown_54h);
writer.Write(this.Stride);
writer.Write((uint)this.Format);
writer.Write(this.Unknown_5Ch);
writer.Write(this.Levels);
writer.Write(this.Unknown_5Eh);
writer.Write(this.Unknown_60h);
writer.Write(this.Unknown_64h);
writer.Write(this.Unknown_68h);
writer.Write(this.Unknown_6Ch);
writer.Write(this.DataPointer);
writer.Write(this.Unknown_78h);
writer.Write(this.Unknown_7Ch);
writer.Write(this.Unknown_80h);
writer.Write(this.Unknown_84h);
writer.Write(this.Unknown_88h);
writer.Write(this.Unknown_8Ch);
}
/// <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());
list.Add(Data);
return list.ToArray();
}
public override string ToString()
{
return "Texture: " + Width.ToString() + "x" + Height.ToString() + ": " + Name;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class TextureData : ResourceGraphicsBlock
{
public override long BlockLength
{
get
{
return FullData.Length;
}
}
public byte[] FullData { get; set; }
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
uint format = Convert.ToUInt32(parameters[0]);
int Width = Convert.ToInt32(parameters[1]);
int Height = Convert.ToInt32(parameters[2]);
int Levels = Convert.ToInt32(parameters[3]);
int Stride = Convert.ToInt32(parameters[4]);
int fullLength = 0;
int length = Stride * Height;
for (int i = 0; i < Levels; i++)
{
fullLength += length;
length /= 4;
}
FullData = reader.ReadBytes(fullLength);
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
writer.Write(FullData);
}
}
public enum TextureFormat : uint
{
D3DFMT_A8R8G8B8 = 21,
D3DFMT_A1R5G5B5 = 25,
D3DFMT_A8 = 28,
D3DFMT_A8B8G8R8 = 32,
D3DFMT_L8 = 50,
// fourCC
D3DFMT_DXT1 = 0x31545844,
D3DFMT_DXT3 = 0x33545844,
D3DFMT_DXT5 = 0x35545844,
D3DFMT_ATI1 = 0x31495441,
D3DFMT_ATI2 = 0x32495441,
D3DFMT_BC7 = 0x20374342,
//UNKNOWN
}
public static class TextureFormats
{
public static SharpDX.DXGI.Format GetDXGIFormat(TextureFormat fmt)
{
SharpDX.DXGI.Format format = SharpDX.DXGI.Format.Unknown;
switch (fmt)
{
// compressed
case TextureFormat.D3DFMT_DXT1: format = SharpDX.DXGI.Format.BC1_UNorm; break;
case TextureFormat.D3DFMT_DXT3: format = SharpDX.DXGI.Format.BC2_UNorm; break;
case TextureFormat.D3DFMT_DXT5: format = SharpDX.DXGI.Format.BC3_UNorm; break;
case TextureFormat.D3DFMT_ATI1: format = SharpDX.DXGI.Format.BC4_UNorm; break;
case TextureFormat.D3DFMT_ATI2: format = SharpDX.DXGI.Format.BC5_UNorm; break;
case TextureFormat.D3DFMT_BC7: format = SharpDX.DXGI.Format.BC7_UNorm; break;
// uncompressed
case TextureFormat.D3DFMT_A1R5G5B5: format = SharpDX.DXGI.Format.B5G5R5A1_UNorm; break;
case TextureFormat.D3DFMT_A8: format = SharpDX.DXGI.Format.A8_UNorm; break;
case TextureFormat.D3DFMT_A8B8G8R8: format = SharpDX.DXGI.Format.R8G8B8A8_UNorm; break;
case TextureFormat.D3DFMT_L8: format = SharpDX.DXGI.Format.R8_UNorm; break;
case TextureFormat.D3DFMT_A8R8G8B8: format = SharpDX.DXGI.Format.B8G8R8A8_UNorm; break;
}
return format;
}
public static int ByteSize(TextureFormat fmt)
{
switch (fmt)
{
// compressed
case TextureFormat.D3DFMT_DXT1: return 4;// BC1_UNorm
case TextureFormat.D3DFMT_DXT3: return 8;// BC2_UNorm
case TextureFormat.D3DFMT_DXT5: return 8;// BC3_UNorm
case TextureFormat.D3DFMT_ATI1: return 4;// BC4_UNorm
case TextureFormat.D3DFMT_ATI2: return 8;// BC5_UNorm
case TextureFormat.D3DFMT_BC7: return 8;// BC7_UNorm
// uncompressed
case TextureFormat.D3DFMT_A1R5G5B5: return 16;// B5G5R5A1_UNorm
case TextureFormat.D3DFMT_A8: return 8;// A8_UNorm
case TextureFormat.D3DFMT_A8B8G8R8: return 32;// R8G8B8A8_UNorm
case TextureFormat.D3DFMT_L8: return 8;// R8_UNorm
case TextureFormat.D3DFMT_A8R8G8B8: return 32;// B8G8R8A8_UNorm
default: return 0;
}
}
public static void ComputePitch(Format fmt, int width, int height, out int rowPitch, out int slicePitch, uint flags)
{
int nbw, nbh;
switch (fmt)
{
case Format.BC1_Typeless:
case Format.BC1_UNorm:
case Format.BC1_UNorm_SRgb:
case Format.BC4_Typeless:
case Format.BC4_UNorm:
case Format.BC4_SNorm:
nbw = Math.Max(1, (width + 3) / 4);
nbh = Math.Max(1, (height + 3) / 4);
rowPitch = nbw * 8;
slicePitch = rowPitch * nbh;
break;
case Format.BC2_Typeless:
case Format.BC2_UNorm:
case Format.BC2_UNorm_SRgb:
case Format.BC3_Typeless:
case Format.BC3_UNorm:
case Format.BC3_UNorm_SRgb:
case Format.BC5_Typeless:
case Format.BC5_UNorm:
case Format.BC5_SNorm:
case Format.BC6H_Typeless:
case Format.BC6H_Uf16:
case Format.BC6H_Sf16:
case Format.BC7_Typeless:
case Format.BC7_UNorm:
case Format.BC7_UNorm_SRgb:
nbw = Math.Max(1, (width + 3) / 4);
nbh = Math.Max(1, (height + 3) / 4);
rowPitch = nbw * 16;
slicePitch = rowPitch * nbh;
break;
case Format.R8G8_B8G8_UNorm:
case Format.G8R8_G8B8_UNorm:
case Format.YUY2:
rowPitch = ((width + 1) >> 1) * 4;
slicePitch = rowPitch * height;
break;
case Format.Y210:
case Format.Y216:
rowPitch = ((width + 1) >> 1) * 8;
slicePitch = rowPitch * height;
break;
case Format.NV12:
case Format.Opaque420:
rowPitch = ((width + 1) >> 1) * 2;
slicePitch = rowPitch * (height + ((height + 1) >> 1));
break;
case Format.P010:
case Format.P016:
//case Format.XBOX_DXGI_FORMAT_D16_UNORM_S8_UINT:
//case Format.XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS:
//case Format.XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT:
rowPitch = ((width + 1) >> 1) * 4;
slicePitch = rowPitch * (height + ((height + 1) >> 1));
break;
case Format.NV11:
rowPitch = ((width + 3) >> 2) * 4;
slicePitch = rowPitch * height * 2;
break;
//case Format.WIN10_DXGI_FORMAT_P208:
// rowPitch = ((width + 1) >> 1) * 2;
// slicePitch = rowPitch * height * 2;
// break;
//case Format.WIN10_DXGI_FORMAT_V208:
// rowPitch = width;
// slicePitch = rowPitch * (height + (((height + 1) >> 1) * 2));
// break;
//case Format.WIN10_DXGI_FORMAT_V408:
// rowPitch = width;
// slicePitch = rowPitch * (height + ((height >> 1) * 4));
// break;
default:
int bpp = FormatHelper.SizeOfInBytes(fmt) * 8;
// Default byte alignment
rowPitch = (width * bpp + 7) / 8;
slicePitch = rowPitch * height;
break;
}
}
}
}
+116
View File
@@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class VehicleRecordList : ResourceFileBase
{
public override long BlockLength => 0x20;
public ResourceSimpleList64<VehicleRecordEntry> Entries;
public VehicleRecordList()
{
this.Entries = new ResourceSimpleList64<VehicleRecordEntry>();
}
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
this.Entries = reader.ReadBlock<ResourceSimpleList64<VehicleRecordEntry>>();
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
writer.WriteBlock(this.Entries);
}
public override Tuple<long, IResourceBlock>[] GetParts()
{
return new Tuple<long, IResourceBlock>[] {
new Tuple<long, IResourceBlock>(16, Entries)
};
}
}
public class VehicleRecordEntry : ResourceSystemBlock
{
// this looks exactly like an rrr entry:
// -> http://www.gtamodding.com/wiki/Carrec
public override long BlockLength => 0x20;
// structure data
public uint Time;
public short VelocityX;
public short VelocityY;
public short VelocityZ;
public sbyte RightX;
public sbyte RightY;
public sbyte RightZ;
public sbyte TopX;
public sbyte TopY;
public sbyte TopZ;
public byte SteeringAngle;
public byte GasPedalPower;
public byte BrakePedalPower;
public byte HandbrakeUsed;
public float PositionX;
public float PositionY;
public float PositionZ;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.Time = reader.ReadUInt32();
this.VelocityX = reader.ReadInt16();
this.VelocityY = reader.ReadInt16();
this.VelocityZ = reader.ReadInt16();
this.RightX = (sbyte)reader.ReadByte();
this.RightY = (sbyte)reader.ReadByte();
this.RightZ = (sbyte)reader.ReadByte();
this.TopX = (sbyte)reader.ReadByte();
this.TopY = (sbyte)reader.ReadByte();
this.TopZ = (sbyte)reader.ReadByte();
this.SteeringAngle = reader.ReadByte();
this.GasPedalPower = reader.ReadByte();
this.BrakePedalPower = reader.ReadByte();
this.HandbrakeUsed = reader.ReadByte();
this.PositionX = reader.ReadSingle();
this.PositionY = reader.ReadSingle();
this.PositionZ = reader.ReadSingle();
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
// write structure data
writer.Write(this.Time);
writer.Write(this.VelocityX);
writer.Write(this.VelocityY);
writer.Write(this.VelocityZ);
writer.Write(this.RightX);
writer.Write(this.RightY);
writer.Write(this.RightZ);
writer.Write(this.TopX);
writer.Write(this.TopY);
writer.Write(this.TopZ);
writer.Write(this.SteeringAngle);
writer.Write(this.GasPedalPower);
writer.Write(this.BrakePedalPower);
writer.Write(this.HandbrakeUsed);
writer.Write(this.PositionX);
writer.Write(this.PositionY);
writer.Write(this.PositionZ);
}
}
}
File diff suppressed because it is too large Load Diff
+107
View File
@@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class WaypointRecordList : ResourceFileBase
{
public override long BlockLength => 0x30;
public uint Unknown_10h; // 0x00000000
public uint Unknown_14h; // 0x00000000
public ulong EntriesPointer;
public uint EntriesCount;
public uint Unknown_24h; // 0x00000000
public uint Unknown_28h; // 0x00000000
public uint Unknown_2Ch; // 0x00000000
public ResourceSimpleArray<WaypointRecordEntry> Entries;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
this.Unknown_10h = reader.ReadUInt32();
this.Unknown_14h = reader.ReadUInt32();
this.EntriesPointer = reader.ReadUInt64();
this.EntriesCount = reader.ReadUInt32();
this.Unknown_24h = reader.ReadUInt32();
this.Unknown_28h = reader.ReadUInt32();
this.Unknown_2Ch = reader.ReadUInt32();
this.Entries = reader.ReadBlockAt<ResourceSimpleArray<WaypointRecordEntry>>(
this.EntriesPointer, // offset
this.EntriesCount
);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
//// update structure data
//this.EntriesPointer = (ulong)(this.Entries?.Position ?? 0);
//this.EntriesCount = (uint)(this.Entries?.Count ?? 0);
// write structure data
writer.Write(this.Unknown_10h);
writer.Write(this.Unknown_14h);
writer.Write(this.EntriesPointer);
writer.Write(this.EntriesCount);
writer.Write(this.Unknown_24h);
writer.Write(this.Unknown_28h);
writer.Write(this.Unknown_2Ch);
}
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>(base.GetReferences());
if (Entries != null) list.Add(Entries);
return list.ToArray();
}
}
public class WaypointRecordEntry : ResourceSystemBlock
{
public override long BlockLength => 20;
public float PositionX;
public float PositionY;
public float PositionZ;
public ushort Unk0;
public ushort Unk1;
public ushort Unk2;
public ushort Unk3;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.PositionX = reader.ReadSingle();
this.PositionY = reader.ReadSingle();
this.PositionZ = reader.ReadSingle();
this.Unk0 = reader.ReadUInt16();
this.Unk1 = reader.ReadUInt16();
this.Unk2 = reader.ReadUInt16();
this.Unk3 = reader.ReadUInt16();
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
// write structure data
writer.Write(this.PositionX);
writer.Write(this.PositionY);
writer.Write(this.PositionZ);
writer.Write(this.Unk0);
writer.Write(this.Unk1);
writer.Write(this.Unk2);
writer.Write(this.Unk3);
}
}
}
+251
View File
@@ -0,0 +1,251 @@
/*
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class GTACrypto
{
public static byte[] DecryptAES(byte[] data)
{
return DecryptAESData(data, GTA5Keys.PC_AES_KEY);
}
public static byte[] DecryptAESData(byte[] data, byte[] key, int rounds = 1)
{
var rijndael = Rijndael.Create();
rijndael.KeySize = 256;
rijndael.Key = key;
rijndael.BlockSize = 128;
rijndael.Mode = CipherMode.ECB;
rijndael.Padding = PaddingMode.None;
var buffer = (byte[])data.Clone();
var length = data.Length - data.Length % 16;
// decrypt...
if (length > 0)
{
var decryptor = rijndael.CreateDecryptor();
for (var roundIndex = 0; roundIndex < rounds; roundIndex++)
decryptor.TransformBlock(buffer, 0, length, buffer, 0);
}
return buffer;
}
public static byte[] EncryptAESData(byte[] data, byte[] key, int rounds = 1)
{
var rijndael = Rijndael.Create();
rijndael.KeySize = 256;
rijndael.Key = key;
rijndael.BlockSize = 128;
rijndael.Mode = CipherMode.ECB;
rijndael.Padding = PaddingMode.None;
var buffer = (byte[])data.Clone();
var length = data.Length - data.Length % 16;
// encrypt...
if (length > 0)
{
var encryptor = rijndael.CreateEncryptor();
for (var roundIndex = 0; roundIndex < rounds; roundIndex++)
encryptor.TransformBlock(buffer, 0, length, buffer, 0);
}
return buffer;
}
public static byte[] GetNGKey(string name, uint length)
{
uint hash = GTA5Hash.CalculateHash(name);
uint keyidx = (hash + length + (101 - 40)) % 0x65;
return GTA5Keys.PC_NG_KEYS[keyidx];
}
public static byte[] DecryptNG(byte[] data, string name, uint length)
{
byte[] key = GetNGKey(name, length);
return DecryptNG(data, key);
}
public static byte[] DecryptNG(byte[] data, byte[] key)
{
var decryptedData = new byte[data.Length];
var keyuints = new uint[key.Length / 4];
Buffer.BlockCopy(key, 0, keyuints, 0, key.Length);
for (int blockIndex = 0; blockIndex < data.Length / 16; blockIndex++)
{
var encryptedBlock = new byte[16];
Array.Copy(data, 16 * blockIndex, encryptedBlock, 0, 16);
var decryptedBlock = DecryptNGBlock(encryptedBlock, keyuints);
Array.Copy(decryptedBlock, 0, decryptedData, 16 * blockIndex, 16);
}
if (data.Length % 16 != 0)
{
var left = data.Length % 16;
Buffer.BlockCopy(data, data.Length - left, decryptedData, data.Length - left, left);
}
return decryptedData;
}
public static byte[] DecryptNGBlock(byte[] data, uint[] key)
{
var buffer = data;
// prepare key...
var subKeys = new uint[17][];
for (int i = 0; i < 17; i++)
{
subKeys[i] = new uint[4];
subKeys[i][0] = key[4 * i + 0];
subKeys[i][1] = key[4 * i + 1];
subKeys[i][2] = key[4 * i + 2];
subKeys[i][3] = key[4 * i + 3];
}
buffer = DecryptNGRoundA(buffer, subKeys[0], GTA5Keys.PC_NG_DECRYPT_TABLES[0]);
buffer = DecryptNGRoundA(buffer, subKeys[1], GTA5Keys.PC_NG_DECRYPT_TABLES[1]);
for (int k = 2; k <= 15; k++)
buffer = DecryptNGRoundB(buffer, subKeys[k], GTA5Keys.PC_NG_DECRYPT_TABLES[k]);
buffer = DecryptNGRoundA(buffer, subKeys[16], GTA5Keys.PC_NG_DECRYPT_TABLES[16]);
return buffer;
}
// round 1,2,16
public static byte[] DecryptNGRoundA(byte[] data, uint[] key, uint[][] table)
{
var x1 =
table[0][data[0]] ^
table[1][data[1]] ^
table[2][data[2]] ^
table[3][data[3]] ^
key[0];
var x2 =
table[4][data[4]] ^
table[5][data[5]] ^
table[6][data[6]] ^
table[7][data[7]] ^
key[1];
var x3 =
table[8][data[8]] ^
table[9][data[9]] ^
table[10][data[10]] ^
table[11][data[11]] ^
key[2];
var x4 =
table[12][data[12]] ^
table[13][data[13]] ^
table[14][data[14]] ^
table[15][data[15]] ^
key[3];
var result = new byte[16];
Array.Copy(BitConverter.GetBytes(x1), 0, result, 0, 4);
Array.Copy(BitConverter.GetBytes(x2), 0, result, 4, 4);
Array.Copy(BitConverter.GetBytes(x3), 0, result, 8, 4);
Array.Copy(BitConverter.GetBytes(x4), 0, result, 12, 4);
return result;
}
// round 3-15
public static byte[] DecryptNGRoundB(byte[] data, uint[] key, uint[][] table)
{
var x1 =
table[0][data[0]] ^
table[7][data[7]] ^
table[10][data[10]] ^
table[13][data[13]] ^
key[0];
var x2 =
table[1][data[1]] ^
table[4][data[4]] ^
table[11][data[11]] ^
table[14][data[14]] ^
key[1];
var x3 =
table[2][data[2]] ^
table[5][data[5]] ^
table[8][data[8]] ^
table[15][data[15]] ^
key[2];
var x4 =
table[3][data[3]] ^
table[6][data[6]] ^
table[9][data[9]] ^
table[12][data[12]] ^
key[3];
//var result = new byte[16];
//Array.Copy(BitConverter.GetBytes(x1), 0, result, 0, 4);
//Array.Copy(BitConverter.GetBytes(x2), 0, result, 4, 4);
//Array.Copy(BitConverter.GetBytes(x3), 0, result, 8, 4);
//Array.Copy(BitConverter.GetBytes(x4), 0, result, 12, 4);
//return result;
var result = new byte[16];
result[0] = (byte)((x1 >> 0) & 0xFF);
result[1] = (byte)((x1 >> 8) & 0xFF);
result[2] = (byte)((x1 >> 16) & 0xFF);
result[3] = (byte)((x1 >> 24) & 0xFF);
result[4] = (byte)((x2 >> 0) & 0xFF);
result[5] = (byte)((x2 >> 8) & 0xFF);
result[6] = (byte)((x2 >> 16) & 0xFF);
result[7] = (byte)((x2 >> 24) & 0xFF);
result[8] = (byte)((x3 >> 0) & 0xFF);
result[9] = (byte)((x3 >> 8) & 0xFF);
result[10] = (byte)((x3 >> 16) & 0xFF);
result[11] = (byte)((x3 >> 24) & 0xFF);
result[12] = (byte)((x4 >> 0) & 0xFF);
result[13] = (byte)((x4 >> 8) & 0xFF);
result[14] = (byte)((x4 >> 16) & 0xFF);
result[15] = (byte)((x4 >> 24) & 0xFF);
return result;
}
}
}
File diff suppressed because it is too large Load Diff
+254
View File
@@ -0,0 +1,254 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class JenkHash
{
public JenkHashInputEncoding Encoding { get; set; }
public string Text { get; set; }
public int HashInt { get; set; }
public uint HashUint { get; set; }
public string HashHex { get; set; }
public JenkHash(string text, JenkHashInputEncoding encoding)
{
Encoding = encoding;
Text = text;
HashUint = GenHash(text, encoding);
HashInt = (int)HashUint;
HashHex = "0x" + HashUint.ToString("X");
}
public static uint GenHash(string text, JenkHashInputEncoding encoding)
{
uint h = 0;
byte[] chars;
switch (encoding)
{
default:
case JenkHashInputEncoding.UTF8:
chars = UTF8Encoding.UTF8.GetBytes(text);
break;
case JenkHashInputEncoding.ASCII:
chars = ASCIIEncoding.ASCII.GetBytes(text);
break;
}
for (uint i = 0; i < chars.Length; i++)
{
h += chars[i];
h += (h << 10);
h ^= (h >> 6);
}
h += (h << 3);
h ^= (h >> 11);
h += (h << 15);
return h;
}
public static uint GenHash(string text)
{
uint h = 0;
for (int i = 0; i < text.Length; i++)
{
h += (byte)text[i];
h += (h << 10);
h ^= (h >> 6);
}
h += (h << 3);
h ^= (h >> 11);
h += (h << 15);
return h;
}
public static uint GenHash(byte[] data)
{
uint h = 0;
for (uint i = 0; i < data.Length; i++)
{
h += data[i];
h += (h << 10);
h ^= (h >> 6);
}
h += (h << 3);
h ^= (h >> 11);
h += (h << 15);
return h;
}
}
public enum JenkHashInputEncoding
{
UTF8 = 0,
ASCII = 1,
}
public class JenkIndMatch
{
public string Hash { get; set; }
public string Value { get; set; }
public double Score { get; set; }
public JenkIndMatch(string hash, string val)
{
Hash = hash;
Value = val;
CalculateScore();
}
public void CalculateScore()
{
int wordlength = 0;
int wordrank = 0;
string okwordsymbs = " _-.";
string goodwordsymbs = "_";
for (int i = 0; i < Value.Length; i++)
{
char c = Value[i];
bool wordchar = (char.IsLetter(c) || char.IsDigit(c) || goodwordsymbs.Contains(c));
if (wordchar)
{
wordlength++;
}
else if (okwordsymbs.Contains(c))
{
//wordlength++; //don't add this to the score, but allow it to continue the chain
}
else
{
if (wordlength > 2)
{
wordrank += wordlength; //linear word increment, ignoring 1-2char matches
}
wordlength = 0;
}
//wordrank += wordlength; //each sequential letter in a word contributes more to the rank, ie. 1+2+3+4+...
}
if (wordlength > 2)
{
wordrank += wordlength; //linear word increment, ignoring 1-2char matches
}
if (Value.Length > 0)
{
//the max value for a given length when 1+2+3+4+5+..n = n(n+1)/2
//double n = (double)Value.Length;
//double maxscore = n * (n + 1.0) * 0.5;
double n = (double)Value.Length;
Score = (((double)wordrank) / n);
//Score = (((double)wordrank));
}
else
{
Score = 0.0;
}
}
public override string ToString()
{
return string.Format("{0} -> {1} ({2:0.##})", Hash, Value, Score);
}
}
public class JenkIndProblem
{
public string Filename { get; set; }
public string Excuse { get; set; }
public int Line { get; set; }
public JenkIndProblem(string filepath, string excuse, int line)
{
Filename = Path.GetFileName(filepath);
Excuse = excuse;
Line = line;
}
public override string ToString()
{
return string.Format("{0} : {1} at line {2}", Filename, Excuse, Line);
}
}
public static class JenkIndex
{
public static Dictionary<uint, string> Index = new Dictionary<uint, string>();
private static object syncRoot = new object();
public static void Clear()
{
lock (syncRoot)
{
Index.Clear();
}
}
public static bool Ensure(string str)
{
uint hash = JenkHash.GenHash(str);
if (hash == 0) return true;
lock (syncRoot)
{
if (!Index.ContainsKey(hash))
{
Index.Add(hash, str);
return false;
}
}
return true;
}
public static string GetString(uint hash)
{
string res;
lock (syncRoot)
{
if (!Index.TryGetValue(hash, out res))
{
res = hash.ToString();
}
}
return res;
}
public static string TryGetString(uint hash)
{
string res;
lock (syncRoot)
{
if (!Index.TryGetValue(hash, out res))
{
res = string.Empty;
}
}
return res;
}
}
}