using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace FF8
{
public class Debug_battleDat
{
int id;
readonly EntityType entityType;
byte[] buffer;
///
/// V is the scale dividor. For now in Battle and World modules I'm dividing native f16 to 2048f
///
public const float V = 2048.0f;
public struct DatFile
{
public uint cSections;
public uint[] pSections;
public uint eof;
}
public DatFile datFile;
#region section 1 Skeleton
[StructLayout(LayoutKind.Sequential,Pack = 1,Size =16)]
public struct Skeleton
{
public ushort cBones;
public ushort scale;
public ushort unk2;
public ushort unk3;
public ushort unk4;
public ushort unk5;
public ushort unk6;
public ushort unk7;
public Bone[] bones;
public Vector3 GetScale => new Vector3(scale/V*12, scale/V*12, scale/V*12);
}
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 48)]
public struct Bone
{
public ushort parentId;
public short boneSize;
private short unk1; //360
private short unk2; //360
private short unk3; //360
private short unk4;
private short unk5;
private short unk6;
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 28 )]
public byte[] Unk;
public float Size { get => boneSize / V; }
public float Unk1 { get => unk1 / 4096.0f * 360.0f; }
public float Unk2 { get => unk2 / 4096.0f * 360.0f; }
public float Unk3 { get => unk3 / 4096.0f * 360.0f; }
public float Unk4 { get => unk4 / 4096.0f; }
public float Unk5 { get => unk5 / 4096.0f; }
public float Unk6 { get => unk6 / 4096.0f; }
}
///
/// Skeleton data section
///
///
///
///
private void ReadSection1(uint v, MemoryStream ms, BinaryReader br)
{
ms.Seek(v, SeekOrigin.Begin);
#if _WINDOWS //looks like Linux Mono doesn't like marshalling structure with LPArray to Bone[]
skeleton = Extended.ByteArrayToStructure(br.ReadBytes(16));
#else
skeleton = new Skeleton()
{
cBones = br.ReadUInt16(),
scale = br.ReadUInt16(),
unk2 = br.ReadUInt16(),
unk3 = br.ReadUInt16(),
unk4 = br.ReadUInt16(),
unk5 = br.ReadUInt16(),
unk6 = br.ReadUInt16(),
unk7 = br.ReadUInt16()
};
#endif
skeleton.bones = new Bone[skeleton.cBones];
for (int i = 0; i < skeleton.cBones; i++)
skeleton.bones[i] = Extended.ByteArrayToStructure(br.ReadBytes(48));
return;
}
public Skeleton skeleton;
#endregion
#region section 2 Geometry
public struct Geometry
{
public uint cObjects;
public uint[] pObjects;
public Object[] objects;
public uint cTotalVert;
}
public struct Object
{
public ushort cVertices;
public VerticeData[] verticeData;
public ushort cTriangles;
public ushort cQuads;
public ulong padding;
public Triangle[] triangles;
public Quad[] quads;
}
public struct VerticeData
{
public ushort boneId;
public ushort cVertices;
public Vertex[] vertices;
}
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 8)]
public struct Vertex
{
public short x;
public short y;
public short z;
public Vector3 GetVector => new Vector3(-x/ V, -z/V, -y/V);
}
[StructLayout(LayoutKind.Sequential, Pack =1, Size =16)]
public struct Triangle
{
private ushort A;
private ushort B;
private ushort C;
public UV vta;
public UV vtb;
public ushort texUnk;
public UV vtc;
public ushort u;
public ushort A1 { get => (ushort)(A & 0xFFF); set => A = value; }
public ushort B1 { get => (ushort)(B & 0xFFF); set => B = value; }
public ushort C1 { get => (ushort)(C & 0xFFF); set => C = value; }
public byte textureIndex { get => (byte)((texUnk >> 6) & 0b111); }
}
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 20)]
public struct Quad
{
private ushort A;
private ushort B;
private ushort C;
private ushort D;
public UV vta;
public ushort texUnk;
public UV vtb;
public ushort u;
public UV vtc;
public UV vtd;
public ushort A1 { get => (ushort)(A & 0xFFF); set => A = value; }
public ushort B1 { get => (ushort)(B & 0xFFF); set => B = value; }
public ushort C1 { get => (ushort)(C & 0xFFF); set => C = value; }
public ushort D1 { get => (ushort)(D & 0xFFF); set => D = value; }
public byte textureIndex { get => (byte)((texUnk >> 6) & 0b111); }
}
[StructLayout(LayoutKind.Sequential, Pack =1,Size =2)]
public struct UV
{
public byte U;
public byte V;
public float U1(float h=128f) { return U / h; }
public float V1(float w=128f) { return V > 128 ? //if bigger than 128, then multitexture index to odd
(V - 128f)/w
: w==32 ? //if equals 32, then it's weapon texture and should be in range of 96-128
(V-96)/w
: V/w; } //if none of these cases, then divide by resolution;
public override string ToString()
{
return $"{U};{U1()};{V};{V1()}";
}
}
public Geometry geometry;
///
/// Geometry section
///
///
///
///
private void ReadSection2(uint v, MemoryStream ms, BinaryReader br)
{
ms.Seek(v, SeekOrigin.Begin);
geometry = new Geometry { cObjects = br.ReadUInt32() };
geometry.pObjects = new uint[geometry.cObjects];
for (int i = 0; i < geometry.cObjects; i++)
geometry.pObjects[i] = br.ReadUInt32();
geometry.objects = new Object[geometry.cObjects];
for (int i = 0; i < geometry.cObjects; i++)
geometry.objects[i] = ReadGeometryObject(v+geometry.pObjects[i], ms, br);
geometry.cTotalVert = br.ReadUInt32();
}
private Object ReadGeometryObject(uint v, MemoryStream ms, BinaryReader br)
{
ms.Seek(v, SeekOrigin.Begin);
Object @object = new Object { cVertices = br.ReadUInt16() };
@object.verticeData = new VerticeData[@object.cVertices];
if (ms.Position + @object.cVertices * 6 >= ms.Length)
return @object;
for (int n = 0; n < @object.cVertices; n++){
@object.verticeData[n].boneId = br.ReadUInt16();
@object.verticeData[n].cVertices = br.ReadUInt16();
@object.verticeData[n].vertices = new Vertex[@object.verticeData[n].cVertices];
for (int i = 0; i < @object.verticeData[n].cVertices; i++)
@object.verticeData[n].vertices[i] = Extended.ByteArrayToStructure(br.ReadBytes(6));}
ms.Seek(4-(ms.Position%4 == 0 ? 4 : ms.Position%4), SeekOrigin.Current);
@object.cTriangles = br.ReadUInt16();
@object.cQuads = br.ReadUInt16();
@object.padding = br.ReadUInt64();
@object.triangles = new Triangle[@object.cTriangles];
if (@object.cTriangles == 0 && @object.cQuads == 0)
return @object;
@object.quads = new Quad[@object.cQuads];
for (int i = 0; i < @object.cTriangles; i++)
@object.triangles[i] = Extended.ByteArrayToStructure(br.ReadBytes(16));
for (int i = 0; i < @object.cQuads; i++)
@object.quads[i] = Extended.ByteArrayToStructure(br.ReadBytes(20));
return @object;
}
///
/// This method returns geometry data AFTER animation matrix translations, local position/rotation translations. This is the final step of calculation.
/// This data should be used only by Renderer. Any translations/vertices manipulation should happen inside this method or earlier
///
/// Monsters can have more than one object. Treat it like multi-model geometry. They are all needed to build whole model
/// a Vector3 to set global position
/// a Quaternion to set the correct rotation. 1=90, 2=180 ...
/// an animation pointer. Animation 0 is always idle
/// an animation frame from animation id. You should pass incrementing frame and reset to 0 when frameCount max is hit
/// FEATURE: This float (0.0 - 1.0) is used in Linear interpolation in animation frames blending. 0.0 means frameN, 1.0 means FrameN+1. Usually this should be a result of deltaTime to see if computer is capable of rendering smooth animations rather than constant 15 FPS
///
public Tuple GetVertexPositions(int objectId, Vector3 position,Quaternion rotation, int animationId, int animationFrame, float step)
{
Object obj = geometry.objects[objectId];
if (animationFrame >= animHeader.animations[animationId].animationFrames.Length || animationFrame<0)
animationFrame = 0;
AnimationFrame frame = animHeader.animations[animationId].animationFrames[animationFrame];
AnimationFrame nextFrame = animationFrame +1 >= animHeader.animations[animationId].animationFrames.Length
? animHeader.animations[animationId].animationFrames[0]
: animHeader.animations[animationId].animationFrames[animationFrame+1];
List vpt = new List();
List> verts = new List>();
int i = 0;
foreach (var a in obj.verticeData)
foreach (var b in a.vertices)
verts.Add(CalculateFrame(new Tuple(b.GetVector, a.boneId),frame,nextFrame, step));
byte[] texturePointers = new byte[obj.cTriangles + obj.cQuads*2];
Vector3 snapToGround = Vector3.Zero;
FixScaleYOffset(out snapToGround);
Vector3 translationPosition = position + Vector3.SmoothStep(frame.Position, nextFrame.Position, step) + snapToGround;
for (;i VerticeC = verts[ obj.triangles[i].C1];
Vector3 VerticeDataC = VerticeC.Item1;
VerticeDataC = Vector3.Transform(VerticeDataC, Matrix.CreateFromQuaternion(rotation));
VerticeDataC = Vector3.Transform(VerticeDataC, Matrix.CreateTranslation(translationPosition));
////////////////////=============VERTEX A========\\\\\\\\\\\\\\\\\\\\\
Tuple VerticeA = verts[obj.triangles[i].A1];
Vector3 VerticeDataA = VerticeA.Item1;
VerticeDataA = Vector3.Transform(VerticeDataA, Matrix.CreateFromQuaternion(rotation));
VerticeDataA = Vector3.Transform(VerticeDataA, Matrix.CreateTranslation(translationPosition));
////////////////////=============VERTEX B========\\\\\\\\\\\\\\\\\\\\\
Tuple VerticeB = verts[obj.triangles[i].B1];
Vector3 VerticeDataB = VerticeB.Item1;
VerticeDataB = Vector3.Transform(VerticeDataB, Matrix.CreateFromQuaternion(rotation));
VerticeDataB = Vector3.Transform(VerticeDataB, Matrix.CreateTranslation(translationPosition));
///
///=/=/=/=/==/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=
var prevarTexT = textures.textures[obj.triangles[i].textureIndex];
vpt.Add(new VertexPositionTexture(VerticeDataC, new Vector2(obj.triangles[i].vta.U1(prevarTexT.Width), obj.triangles[i].vta.V1(prevarTexT.Height))));
vpt.Add(new VertexPositionTexture(VerticeDataA, new Vector2(obj.triangles[i].vtb.U1(prevarTexT.Width), obj.triangles[i].vtb.V1(prevarTexT.Height))));
vpt.Add(new VertexPositionTexture(VerticeDataB, new Vector2(obj.triangles[i].vtc.U1(prevarTexT.Width), obj.triangles[i].vtc.V1(prevarTexT.Height))));
texturePointers[i] = obj.triangles[i].textureIndex;
}
for (i = 0; i < obj.cQuads; i++)
{
////////////////////=============VERTEX A========\\\\\\\\\\\\\\\\\\\\\
Tuple VerticeA = verts[obj.quads[i].A1];
Vector3 VerticeDataA = VerticeA.Item1;
VerticeDataA = Vector3.Transform(VerticeDataA, Matrix.CreateFromQuaternion(rotation));
VerticeDataA = Vector3.Transform(VerticeDataA, Matrix.CreateTranslation(translationPosition));
////////////////////=============VERTEX B========\\\\\\\\\\\\\\\\\\\\\
Tuple VerticeB = verts[obj.quads[i].B1];
Vector3 VerticeDataB = VerticeB.Item1;
VerticeDataB = Vector3.Transform(VerticeDataB, Matrix.CreateFromQuaternion(rotation));
VerticeDataB = Vector3.Transform(VerticeDataB, Matrix.CreateTranslation(translationPosition));
////////////////////=============VERTEX C========\\\\\\\\\\\\\\\\\\\\\
Tuple VerticeC = verts[obj.quads[i].C1];
Vector3 VerticeDataC = VerticeC.Item1;
VerticeDataC = Vector3.Transform(VerticeDataC, Matrix.CreateFromQuaternion(rotation));
VerticeDataC = Vector3.Transform(VerticeDataC, Matrix.CreateTranslation(translationPosition));
////////////////////=============VERTEX D========\\\\\\\\\\\\\\\\\\\\\
Tuple VerticeD = verts[obj.quads[i].D1];
Vector3 VerticeDataD = VerticeD.Item1;
VerticeDataD = Vector3.Transform(VerticeDataD, Matrix.CreateFromQuaternion(rotation));
VerticeDataD = Vector3.Transform(VerticeDataD, Matrix.CreateTranslation(translationPosition));
///
var preVarTex = textures.textures[obj.quads[i].textureIndex];
vpt.Add(new VertexPositionTexture(VerticeDataA, new Vector2(obj.quads[i].vta.U1(preVarTex.Width), obj.quads[i].vta.V1(preVarTex.Height))));
vpt.Add(new VertexPositionTexture(VerticeDataB, new Vector2(obj.quads[i].vtb.U1(preVarTex.Width), obj.quads[i].vtb.V1(preVarTex.Height))));
vpt.Add(new VertexPositionTexture(VerticeDataD, new Vector2(obj.quads[i].vtd.U1(preVarTex.Width), obj.quads[i].vtd.V1(preVarTex.Height))));
vpt.Add(new VertexPositionTexture(VerticeDataA, new Vector2(obj.quads[i].vta.U1(preVarTex.Width), obj.quads[i].vta.V1(preVarTex.Height))));
vpt.Add(new VertexPositionTexture(VerticeDataC, new Vector2(obj.quads[i].vtc.U1(preVarTex.Width), obj.quads[i].vtc.V1(preVarTex.Height))));
vpt.Add(new VertexPositionTexture(VerticeDataD, new Vector2(obj.quads[i].vtd.U1(preVarTex.Width), obj.quads[i].vtd.V1(preVarTex.Height))));
texturePointers[obj.cTriangles+i*2] = obj.quads[i].textureIndex;
texturePointers[obj.cTriangles + i * 2+1] = obj.quads[i].textureIndex;
}
return new Tuple(vpt.ToArray(), texturePointers);
}
///
/// Lazy class to fix Y axis of entities because due to scalling some appeared above or below the stage.
/// Those entities that have so far unknown Y axis are vurnable to DEBUGframe variable
///
///
private void FixScaleYOffset(out Vector3 snapToGround)
{
//snapToGround = Vector3.Zero;
//return;
float fScaleResolver = skeleton.GetScale.Y;
float y = 0f;
switch(entityType)
{
case EntityType.Monster:
switch (GetId)
{
case 68:
y = -300f;
break;
case 21:
case 18:
y = -125;
break;
case 125:
y = -120;
break;
case 25:
y = -100;
break;
case 113:
y = -90;
break;
case 54:
y = -57;
break;
case 119:
case 136:
y = -50;
break;
case 88:
case 100:
y = -30;
break;
case 55:
y = -28;
break;
case 82:
case 142:
y = -27;
break;
case 85:
case 86:
case 87:
case 128:
case 71:
case 73:
case 76:
case 108:
case 15:
case 134:
case 143:
case 17:
y = -25;
break;
case 75:
y = -23;
break;
case 28:
case 29:
case 78:
case 79:
case 120:
case 137:
case 14:
y = -20;
break;
case 60:
y = -19;
break;
case 31:
y = -18;
break;
case 64:
case 72:
case 74:
case 135:
y = -17;
break;
case 4:
case 46:
case 56:
case 59:
case 13:
y = -14;
break;
case 39:
case 40:
y = -12;
break;
case 42:
y = -11;
break;
case 69:
y = -10;
break;
case 57:
y = -6;
break;
case 129:
y = -4;
break;
case 62:
case 23:
case 80:
case 81:
y = -3;
break;
case 96:
y = -2;
break;
case 33:
case 95:
case 37:
case 99:
case 48:
case 124:
break; //f default 0, so no need to explicitely write it again
case 53:
y = 2;
break;
case 19:
y = 3;
break;
case 32:
case 93:
y = 4;
break;
case 52:
y = 5;
break;
case 121:
case 22:
y = 6;
break;
case 9:
case 27:
case 65:
case 35:
case 36:
case 50:
case 12:
case 11:
y = 10;
break;
case 7:
case 16:
y = 15;
break;
case 45:
y = 18;
break;
case 6:
case 43:
case 3:
case 8:
y = 20;
break;
case 1:
y = 24;
break;
case 63:
y = 25;
break;
case 41:
case 24:
y = 30;
break;
case 115:
y = 32;
break;
case 20:
case 10:
case 133:
y = 40;
break;
case 38:
case 49:
y = 50;
break;
case 61:
case 114:
y = 60;
break;
case 89:
case 97:
case 98:
case 111:
y = 62;
break;
case 90:
y = 90;
break;
case 51:
y = 72;
break;
case 66:
y = 80;
break;
case 112:
y = 85;
break;
case 130:
y = 90;
break;
case 5:
case 26:
case 77:
case 30:
case 92:
y = 100;
break;
case 67:
case 132:
y = 150;
break;
case 131:
y = 160;
break;
case 122:
case 84:
y = 180;
break;
case 109:
y = 240;
break;
case 118:
case 140:
case 138:
case 141:
y = 250;
break;
default:
y = Module_battle_debug.DEBUGframe;
break;
}
break;
case EntityType.Character:
case EntityType.Weapon:
switch(GetId)
{
case 0:
y = -30;
break;
case 1:
case 2:
case 8:
y = -32;
break;
case 3:
y = -64;
break;
case 4:
y = -66;
break;
case 5:
y = -60;
break;
case 6:
y = -26;
break;
case 7:
y = -24;
break;
case 9:
y = -36;
break;
case 10:
y = 0;
break;
default:
y = Module_battle_debug.DEBUGframe;
break;
}
break;
}
y = fScaleResolver+ y/10f;
snapToGround = new Vector3(0, y, 0);
}
///
/// Complex function that provides linear interpolation between two matrices of actual to-render animation frame and next frame data for blending
///
/// the tuple that contains bone identificator and vertex
/// current animation frame to render
/// animation frame to render that is AFTER the actual one. If last frame, then usually 0 is the 'next' frame
/// step is variable used to determinate the progress for linear interpolation. I.e. 0 for current frame and 1 for next frame; 0.5 for blend of two frames
///
private Tuple CalculateFrame(Tuple tuple, AnimationFrame frame,AnimationFrame nextFrame, float step)
{
Matrix matrix = frame.boneRot.Item3[tuple.Item2]; //get's bone matrix
Vector3 rootFramePos = new Vector3(
matrix.M11 * tuple.Item1.X + matrix.M41 + matrix.M12 * tuple.Item1.Z + matrix.M13 * -tuple.Item1.Y,
matrix.M21 * tuple.Item1.X + matrix.M42 + matrix.M22 * tuple.Item1.Z + matrix.M23 * -tuple.Item1.Y,
matrix.M31 * tuple.Item1.X + matrix.M43 + matrix.M32 * tuple.Item1.Z + matrix.M33 * -tuple.Item1.Y);
matrix = nextFrame.boneRot.Item3[tuple.Item2];
Vector3 nextFramePos = new Vector3(
matrix.M11 * tuple.Item1.X + matrix.M41 + matrix.M12 * tuple.Item1.Z + matrix.M13 * -tuple.Item1.Y,
matrix.M21 * tuple.Item1.X + matrix.M42 + matrix.M22 * tuple.Item1.Z + matrix.M23 * -tuple.Item1.Y,
matrix.M31 * tuple.Item1.X + matrix.M43 + matrix.M32 * tuple.Item1.Z + matrix.M33 * -tuple.Item1.Y);
rootFramePos = Vector3.Transform(rootFramePos, Matrix.CreateScale(skeleton.GetScale));
nextFramePos = Vector3.Transform(nextFramePos, Matrix.CreateScale(skeleton.GetScale));
rootFramePos = Vector3.SmoothStep(rootFramePos, nextFramePos, step);
return new Tuple(rootFramePos, tuple.Item2);
}
#endregion
#region section 3 Animation
public struct AnimationData
{
public uint cAnimations;
public uint[] pAnimations;
public Animation[] animations;
}
public struct Animation
{
public byte cFrames;
public AnimationFrame[] animationFrames;
}
public struct AnimationFrame
{
private Vector3 position;
public Tuple boneRot;
public Vector3 Position { get => position; set => position = value; }
}
public struct ShortVector
{
public short x;
public short y;
public short z;
}
///
/// Animation section
///
///
///
///
private void ReadSection3(uint v, MemoryStream ms, BinaryReader br)
{
ms.Seek(v, SeekOrigin.Begin);
animHeader = new AnimationData() {cAnimations = br.ReadUInt32() };
animHeader.pAnimations = new uint[animHeader.cAnimations];
for (int i = 0; i < animHeader.cAnimations; i++)
animHeader.pAnimations[i] = br.ReadUInt32();
animHeader.animations = new Animation[animHeader.cAnimations];
for (int i = 0; i < animHeader.cAnimations; i++) //animation
{
ms.Seek(v + animHeader.pAnimations[i], SeekOrigin.Begin);
animHeader.animations[i] = new Animation() {cFrames = br.ReadByte() };
animHeader.animations[i].animationFrames = new AnimationFrame[animHeader.animations[i].cFrames];
ExtapathyExtended.BitReader bitReader = new ExtapathyExtended.BitReader(ms);
for(int n = 0; n(new Vector3[skeleton.cBones], new ShortVector[skeleton.cBones], new Matrix[skeleton.cBones]);
for (int k = 0; k < skeleton.cBones; k++) //bones iterator
{
if (n != 0)
{
animHeader.animations[i].animationFrames[n].boneRot.Item2[k] = new ShortVector() { x = bitReader.ReadRotationType(), y = bitReader.ReadRotationType(), z = bitReader.ReadRotationType() };
var grabber = animHeader.animations[i].animationFrames[n - 1].boneRot.Item2[k];
var adder = animHeader.animations[i].animationFrames[n].boneRot.Item2[k];
animHeader.animations[i].animationFrames[n].boneRot.Item2[k] = new ShortVector() { x = (short)(grabber.x + adder.x), y = (short)(grabber.y + adder.y), z = (short)(grabber.z + adder.z) };
animHeader.animations[i].animationFrames[n].boneRot.Item1[k] = new Vector3(
(animHeader.animations[i].animationFrames[n].boneRot.Item2[k].x) * 360f / 4096f,
(animHeader.animations[i].animationFrames[n].boneRot.Item2[k].y) * 360f / 4096f,
(animHeader.animations[i].animationFrames[n].boneRot.Item2[k].z) * 360f / 4096f);
}
else
{
animHeader.animations[i].animationFrames[n].boneRot.Item2[k] = new ShortVector() { x = bitReader.ReadRotationType(), y = bitReader.ReadRotationType(), z = bitReader.ReadRotationType() };
animHeader.animations[i].animationFrames[n].boneRot.Item1[k] = new Vector3(
(animHeader.animations[i].animationFrames[n].boneRot.Item2[k].x * 360f / 4096f),
(animHeader.animations[i].animationFrames[n].boneRot.Item2[k].y * 360f / 4096f),
(animHeader.animations[i].animationFrames[n].boneRot.Item2[k].z * 360f / 4096f));
}
}
for(int k = 0; k new string(monsterName);
}
public struct Abilities
{
public byte kernelId; //0x2 magic, 0x4 item, 0x8 mosterAbility;
public byte unk;
public ushort abilityId;
}
private void ReadSection7(uint v, MemoryStream ms, BinaryReader br)
{
ms.Seek(v, SeekOrigin.Begin);
}
public Information information;
#endregion
#region section 11 Textures
public struct Textures
{
public uint cTims;
public uint[] pTims;
public uint Eof;
public Texture2D[] textures;
}
private void ReadSection11(uint v, MemoryStream ms, BinaryReader br)
{
ms.Seek(v, SeekOrigin.Begin);
textures = new Textures() { cTims = br.ReadUInt32() };
textures.pTims = new uint[textures.cTims];
for (int i = 0; i < textures.cTims; i++)
textures.pTims[i] = br.ReadUInt32();
textures.Eof = br.ReadUInt32();
textures.textures = new Texture2D[textures.cTims];
for(int i = 0; i
/// Creates new instance of DAT class that provides every sections parsed into structs and helper functions for renderer
///
/// This number is used in c0m(fileId) or d(fileId)cXYZ
/// Supply Monster, character or weapon (0,1,2)
/// Used only in character or weapon to supply for d(fileId)[c/w](additionalFileId)
public Debug_battleDat(int fileId, EntityType entityType, int additionalFileId = -1, Debug_battleDat skeletonReference = null)
{
id = fileId;
Console.WriteLine($"DEBUG: Creating new BattleDat with {fileId},{entityType},{additionalFileId}");
ArchiveWorker aw = new ArchiveWorker(Memory.Archives.A_BATTLE);
string fileName = entityType == EntityType.Monster ? $"c0m{id.ToString("D03")}" :
entityType == EntityType.Character ? $"d{fileId.ToString("x")}c{additionalFileId.ToString("D03")}" :
entityType == EntityType.Weapon ? $"d{fileId.ToString("x")}w{additionalFileId.ToString("D03")}" : string.Empty;
this.entityType = entityType;
if (string.IsNullOrEmpty(fileName))
return;
string path = aw.GetListOfFiles().First(x => x.ToLower().Contains(fileName));
buffer = ArchiveWorker.GetBinaryFile(Memory.Archives.A_BATTLE, path);
#if _WINDOWS
try
{
string targetdir = @"d:\";
if (Directory.Exists(targetdir))
{
var drivei = DriveInfo.GetDrives().Where(x => x.Name.IndexOf(Path.GetPathRoot(targetdir),StringComparison.OrdinalIgnoreCase)>=0).ToArray();
var di = new DirectoryInfo(targetdir);
if(!di.Attributes.HasFlag(FileAttributes.ReadOnly) && drivei.Count()==1 && drivei[0].DriveType == DriveType.Fixed)
Extended.DumpBuffer(buffer, Path.Combine(targetdir,"out.dat"));
}
}
catch(IOException)
{
}
#endif
using (MemoryStream ms = new MemoryStream(buffer))
using (BinaryReader br = new BinaryReader(ms))
{
datFile = new DatFile { cSections = br.ReadUInt32()};
datFile.pSections = new uint[datFile.cSections];
for (int i = 0; i < datFile.cSections; i++)
datFile.pSections[i] = br.ReadUInt32();
datFile.eof = br.ReadUInt32();
switch (this.entityType)
{
case EntityType.Monster:
if (id == 127) return;
ReadSection1(datFile.pSections[0], ms, br);
ReadSection3(datFile.pSections[2], ms, br);
ReadSection2(datFile.pSections[1], ms, br);
//ReadSection4(datFile.pSections[3]);
//ReadSection5(datFile.pSections[4]);
//ReadSection6(datFile.pSections[5]);
ReadSection7(datFile.pSections[6], ms, br);
//ReadSection8(datFile.pSections[7]);
//ReadSection9(datFile.pSections[8]);
//ReadSection10(datFile.pSections[9]);
ReadSection11(datFile.pSections[10], ms, br);
break;
case EntityType.Character:
ReadSection1(datFile.pSections[0], ms, br);
ReadSection3(datFile.pSections[2], ms, br);
ReadSection2(datFile.pSections[1], ms, br);
if(fileId==7 && entityType==EntityType.Character)
ReadSection11(datFile.pSections[8], ms, br);
else
ReadSection11(datFile.pSections[5], ms, br);
break;
case EntityType.Weapon:
if (skeletonReference == null)
{
ReadSection1(datFile.pSections[0], ms, br);
ReadSection3(datFile.pSections[2], ms, br);
ReadSection2(datFile.pSections[1], ms, br);
ReadSection11(datFile.pSections[6], ms, br);
}
else
{
skeleton = skeletonReference.skeleton;
animHeader = skeletonReference.animHeader;
ReadSection2(datFile.pSections[0], ms, br);
ReadSection11(datFile.pSections[4], ms, br);
}
break;
}
}
}
public int GetId => id;
}
}