using System.Collections.Generic; using System.IO; using System.Numerics; using ACE.DatLoader.Entity; using ACE.Entity.Enum; namespace ACE.DatLoader.FileTypes { /// /// These are client_portal.dat files starting with 0x02. /// They are basically 3D model descriptions. /// /// /// A big huge thank you to "Pea" for his trailblazing work on decoding this structure. Without his work on this, we might still be decoding models on cave walls. /// [DatFileType(DatFileType.Setup)] public class SetupModel : FileType { public SetupFlags Flags { get; private set; } public bool AllowFreeHeading { get; private set; } public bool HasPhysicsBSP { get; private set; } public List Parts { get; } = new List(); public List ParentIndex { get; } = new List(); public List DefaultScale { get; } = new List(); public Dictionary HoldingLocations { get; } = new Dictionary(); public Dictionary ConnectionPoints { get; } = new Dictionary(); public Dictionary PlacementFrames { get; } = new Dictionary(); public List CylSpheres { get; } = new List(); public List Spheres { get; } = new List(); public float Height { get; private set; } public float Radius { get; private set; } public float StepUpHeight { get; private set; } public float StepDownHeight { get; private set; } public Sphere SortingSphere { get; private set; } = new Sphere(); public Sphere SelectionSphere { get; private set; } = new Sphere(); public Dictionary Lights { get; } = new Dictionary(); public uint DefaultAnimation { get; private set; } public uint DefaultScript { get; private set; } public uint DefaultMotionTable { get; private set; } public uint DefaultSoundTable { get; private set; } public uint DefaultScriptTable { get; private set; } public bool HasMissileFlightPlacement { get; private set; } = false; public override void Unpack(BinaryReader reader) { Id = reader.ReadUInt32(); Flags = (SetupFlags)reader.ReadUInt32(); AllowFreeHeading = (Flags & SetupFlags.AllowFreeHeading) != 0; HasPhysicsBSP = (Flags & SetupFlags.HasPhysicsBSP) != 0; // Get all the GraphicsObjects in this SetupModel. These are all the 01-types. uint numParts = reader.ReadUInt32(); for (int i = 0; i < numParts; i++) Parts.Add(reader.ReadUInt32()); if ((Flags & SetupFlags.HasParent) != 0) { for (int i = 0; i < numParts; i++) ParentIndex.Add(reader.ReadUInt32()); } if ((Flags & SetupFlags.HasDefaultScale) != 0) { for (int i = 0; i < numParts; i++) DefaultScale.Add(reader.ReadVector3()); } HoldingLocations.Unpack(reader); ConnectionPoints.Unpack(reader); int placementsCount = reader.ReadInt32(); for (int i = 0; i < placementsCount; i++) { int key = reader.ReadInt32(); // there is a frame for each Part var placementType = new PlacementType(); placementType.Unpack(reader, (uint)Parts.Count); PlacementFrames.Add(key, placementType); if (key == (int)Placement.MissileFlight) HasMissileFlightPlacement = true; } CylSpheres.Unpack(reader); Spheres.Unpack(reader); Height = reader.ReadSingle(); Radius = reader.ReadSingle(); StepUpHeight = reader.ReadSingle(); StepDownHeight = reader.ReadSingle(); SortingSphere.Unpack(reader); SelectionSphere.Unpack(reader); Lights.Unpack(reader); DefaultAnimation = reader.ReadUInt32(); DefaultScript = reader.ReadUInt32(); DefaultMotionTable = reader.ReadUInt32(); DefaultSoundTable = reader.ReadUInt32(); DefaultScriptTable = reader.ReadUInt32(); } public static SetupModel CreateSimpleSetup() { var setup = new SetupModel(); setup.SortingSphere = Sphere.CreateDummySphere(); setup.SelectionSphere = Sphere.CreateDummySphere(); setup.AllowFreeHeading = true; return setup; } } }