mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2026-05-17 09:36:14 +08:00
R26_dev8 - First public commit
This commit is contained in:
@@ -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
@@ -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
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
//}
|
||||
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user