Esempio n. 1
0
        private void saveButton_Click(object sender, EventArgs e)
        {
            var sfd = new SaveFileDialog();

            sfd.Filter = "MP3 Files (*.mp3)|*.mp3";

            if (sfd.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            if (!SoundFile.Directory.Exists)
            {
                SoundFile.Directory.Create();
            }

            if (!SoundFile.Exists)
            {
                using (var fileStream = SoundFile.Create())
                    CacheContext.ExtractResource(Sound.Resource, fileStream);
            }

            var destSoundFile = new FileInfo(sfd.FileName);

            if (!destSoundFile.Directory.Exists)
            {
                destSoundFile.Directory.Create();
            }

            SoundFile.CopyTo(destSoundFile.FullName);
        }
Esempio n. 2
0
        public override object Execute(List <string> args)
        {
            if (args.Count != 1)
            {
                return(false);
            }

            var binkFile = new FileInfo(args[0]);

            var resourceContext    = new ResourceSerializationContext(CacheContext, Definition.Resource);
            var resourceDefinition = CacheContext.Deserializer.Deserialize <BinkResource>(resourceContext);

            using (var resourceStream = new MemoryStream())
                using (var resourceReader = new BinaryReader(resourceStream))
                    using (var fileStream = binkFile.Create())
                        using (var fileWriter = new BinaryWriter(fileStream))
                        {
                            CacheContext.ExtractResource(Definition.Resource, resourceStream);
                            resourceReader.BaseStream.Position = resourceDefinition.Data.Address.Offset;
                            fileWriter.Write(resourceReader.ReadBytes(resourceDefinition.Data.Size));
                        }

            Console.WriteLine($"Created \"{binkFile.FullName}\" successfully.");

            return(true);
        }
        public override object Execute(List <string> args)
        {
            if (args.Count != 3)
            {
                return(false);
            }

            var variantName   = args[0];
            var fileType      = args[1].ToLower();
            var modelFileName = args[2];

            switch (fileType)
            {
            case "obj":
                break;

            default:
                throw new NotImplementedException(fileType);
            }

            if (Definition.Geometry.Resource == null)
            {
                Console.WriteLine("Render model does not have a resource associated with it");
                return(true);
            }

            //
            // Deserialize the resource definition
            //

            var resourceContext    = new ResourceSerializationContext(CacheContext, Definition.Geometry.Resource);
            var resourceDefinition = CacheContext.Deserializer.Deserialize <RenderGeometryApiResourceDefinition>(resourceContext);

            using (var resourceStream = new MemoryStream())
            {
                //
                // Extract the resource data
                //

                CacheContext.ExtractResource(Definition.Geometry.Resource, resourceStream);

                var modelFile = new FileInfo(modelFileName);

                if (!modelFile.Directory.Exists)
                {
                    modelFile.Directory.Create();
                }

                switch (fileType)
                {
                case "obj":
                    return(ExtractObj(variantName, modelFile, Definition, resourceDefinition, resourceStream));

                default:
                    throw new NotImplementedException(fileType);
                }
            }
        }
Esempio n. 4
0
        protected override void OnLoad(EventArgs e)
        {
            stopButton_Click(this, e);

            if (!SoundFile.Directory.Exists)
            {
                SoundFile.Directory.Create();
            }

            if (SoundFile.Exists)
            {
                SoundFile.Delete();
            }

            using (var fileStream = SoundFile.Create())
                CacheContext.ExtractResource(Sound.Resource, fileStream);

            base.OnLoad(e);
        }
        public override object Execute(List <string> args)
        {
            if (args.Count < 1 || args.Count > 2)
            {
                return(false);
            }

            if (args.Count == 2 && (args[0].ToLower() != "raw"))
            {
                return(false);
            }

            var file = "";

            if (args.Count == 1)
            {
                file = args[0];
            }
            else
            {
                file = args[1];
            }

            var resourceContext = new ResourceSerializationContext(CacheContext, Geometry.Resource);
            var definition      = CacheContext.Deserializer.Deserialize <RenderGeometryApiResourceDefinition>(resourceContext);

            if (args.Count == 2)
            {
                using (var edResourceStream = new MemoryStream())
                    using (var edResourceReader = new EndianReader(edResourceStream, EndianFormat.LittleEndian))
                    {
                        var directory = args[1];
                        if (!Directory.Exists(directory))
                        {
                            Directory.CreateDirectory(directory);
                        }

                        var dataOutDir = directory;

                        for (var i = 0; i < definition.VertexBuffers.Count; i++)
                        {
                            edResourceStream.Position = definition.VertexBuffers[i].Definition.Data.Address.Offset;

                            var vertexBuffer = definition.VertexBuffers[i].Definition;

                            dataOutDir = Path.Combine(directory, $"{i}_{vertexBuffer.Format}_{vertexBuffer.Count}");

                            using (EndianWriter output = new EndianWriter(File.OpenWrite(dataOutDir), EndianFormat.LittleEndian))
                            {
                                byte[] data = edResourceReader.ReadBytes((int)vertexBuffer.Data.Size);
                                output.WriteBlock(data);
                            }
                        }
                    }
            }
            else
            {
                //
                // Convert Blam data to ElDorado data
                //

                using (var fileStream = File.Create(file))
                    using (var fileWriter = new StreamWriter(fileStream))
                    {
                        using (var edResourceStream = new MemoryStream())
                            using (var edResourceReader = new EndianReader(edResourceStream, EndianFormat.LittleEndian))
                            {
                                //
                                // Convert Blam vertex buffers
                                //

                                Console.Write("Converting vertex buffers...");
                                CacheContext.ExtractResource(Geometry.Resource, edResourceStream);

                                for (var i = 0; i < definition.VertexBuffers.Count; i++)
                                {
                                    edResourceStream.Position = definition.VertexBuffers[i].Definition.Data.Address.Offset;

                                    var vertexBuffer = definition.VertexBuffers[i].Definition;

                                    //fileWriter.WriteLine($"Offset = {vertexBuffer.Data.Address.Offset.ToString("X8")} Count = {vertexBuffer.Count} Size = {vertexBuffer.VertexSize}, Format = {vertexBuffer.Format.ToString()}");
                                    //fileWriter.WriteLine(Environment.NewLine);

                                    //fileWriter.WriteLine($"Vertex buffer index: {i}");

                                    switch (vertexBuffer.Format)
                                    {
                                    case VertexBufferFormat.TinyPosition:
                                        for (var j = 0; j < vertexBuffer.Count; j++)
                                        {
                                            fileWriter.WriteLine($"Position = ({edResourceReader.ReadUInt16().ToString("X4")},{edResourceReader.ReadUInt16().ToString("X4")},{edResourceReader.ReadUInt16().ToString("X4")},{edResourceReader.ReadUInt16().ToString("X4")})");
                                            fileWriter.WriteLine($"Normal   = ({edResourceReader.ReadByte().ToString("X2")},{edResourceReader.ReadByte().ToString("X2")},{edResourceReader.ReadByte().ToString("X2")},{edResourceReader.ReadByte().ToString("X2")})");
                                            fileWriter.WriteLine($"Color    = {edResourceReader.ReadUInt32().ToString("X8")}");
                                        }
                                        break;

                                    case VertexBufferFormat.StaticPerVertex:
                                        for (var j = 0; j < vertexBuffer.Count; j++)
                                        {
                                            fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:");
                                            fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}");
                                            fileWriter.WriteLine(Environment.NewLine);
                                        }
                                        break;

                                    case VertexBufferFormat.Skinned:
                                        for (var j = 0; j < vertexBuffer.Count; j++)
                                        {
                                            fileWriter.WriteLine($"{j}:");
                                            fileWriter.WriteLine($"Position X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                            fileWriter.WriteLine($"Texcoord U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle());
                                            fileWriter.WriteLine($"Normal   X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                            fileWriter.WriteLine($"Tangent  X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                            fileWriter.WriteLine($"Binormal X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                            edResourceReader.ReadUInt32();
                                            edResourceReader.ReadUInt32();
                                        }
                                        break;

                                        /*
                                         * case VertexBufferFormat.Unknown1B:
                                         *  var goodCount = 0;
                                         *  for (var j = 0; j < vertexBuffer.Count; j++)
                                         *  {
                                         *      //fileWriter.WriteLine($"Index: {j}:");
                                         *      string values = $"({ edResourceReader.ReadSingle()},{ edResourceReader.ReadSingle()}," +
                                         *          $"{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()}" +
                                         *          $",{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()})";
                                         *      if(values != "(0,0,0,0,0,0,0,0,0)")
                                         *      {
                                         *          goodCount++;
                                         *          //fileWriter.WriteLine($"(1,2,3,4,5,6,7,8,9) = "+values);
                                         *      }
                                         *
                                         *
                                         *      /*
                                         *      fileWriter.WriteLine($"Unknown 1 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 2 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 3 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 4 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 5 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 6 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 7 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 8 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 9 = " + edResourceReader.ReadSingle());
                                         *
                                         *  }
                                         *  //fileWriter.WriteLine($"Valid Unknown1B count = {goodCount}");
                                         *  break;
                                         *
                                         * case VertexBufferFormat.Unknown1A:
                                         *  for (var j = 0; j < vertexBuffer.Count; j++)
                                         *  {
                                         *      //fileWriter.WriteLine($"Index: {j}:");
                                         *      //fileWriter.WriteLine($"Unknown 1 = " + edResourceReader.ReadUInt32().ToString("X8"));
                                         *      fileWriter.WriteLine($"(1,2,3) = ({edResourceReader.ReadUInt32().ToString("X8")},{edResourceReader.ReadUInt32().ToString("X8")},{edResourceReader.ReadUInt32().ToString("X8")})");
                                         *  }
                                         *  break;
                                         *
                                         * case VertexBufferFormat.Rigid:
                                         *  for (var j = 0; j < vertexBuffer.Count; j++)
                                         *  {
                                         *      fileWriter.WriteLine($"{j}:");
                                         *      fileWriter.WriteLine($"Position X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Texcoord U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Normal   X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Tangent  X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Binormal X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *  }
                                         *  break;
                                         *
                                         * case VertexBufferFormat.StaticPerPixel:
                                         *  for (var j = 0; j < vertexBuffer.Count; j++)
                                         *  {
                                         *      fileWriter.WriteLine($"{j} U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle());
                                         *      //fileWriter.WriteLine(Environment.NewLine);
                                         *  }
                                         *  break;
                                         *
                                         * case VertexBufferFormat.AmbientPrt:
                                         *  for (var j = 0; j < vertexBuffer.Count; j++)
                                         *  {
                                         *      fileWriter.WriteLine($"{j} Blend weight = " + edResourceReader.ReadSingle());
                                         *      //fileWriter.WriteLine(Environment.NewLine);
                                         *  }
                                         *  break;
                                         *
                                         *
                                         * case VertexBufferFormat.World:
                                         *  for (var j = 0; j < vertexBuffer.Count; j++)
                                         *  {
                                         *      fileWriter.WriteLine($"{j}:");
                                         *      fileWriter.WriteLine($"Position X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Texcoord U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Normal   X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Tangent  X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Binormal X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *  }
                                         *  break;
                                         *
                                         *
                                         *
                                         */
                                        /*
                                         *  case VertexBufferFormat.QuadraticPrt:
                                         *      for (var j = 0; j < vertexBuffer.Count; j++)
                                         *      {
                                         *          fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:");
                                         *          fileWriter.WriteLine($"A X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"B X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"C X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}");
                                         *          fileWriter.WriteLine(Environment.NewLine);
                                         *      }
                                         *      break;
                                         *
                                         *
                                         *
                                         *  case VertexBufferFormat.Unknown1B:
                                         *      for (var j = 0; j < vertexBuffer.Count; j++)
                                         *      {
                                         *          fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:");
                                         *          fileWriter.WriteLine($"Unknown 1 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 2 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 3 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 4 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 5 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 6 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 7 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 8 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 9 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}");
                                         *          fileWriter.WriteLine(Environment.NewLine);
                                         *      }
                                         *      break;
                                         *
                                         *  case VertexBufferFormat.Decorator:
                                         *      for (var j = 0; j < vertexBuffer.Count; j++)
                                         *      {
                                         *          fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:");
                                         *          fileWriter.WriteLine($"Position X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Texcoord U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Normal   X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}");
                                         *          fileWriter.WriteLine(Environment.NewLine);
                                         *      }
                                         *      break;
                                         *
                                         *  case VertexBufferFormat.LinearPrt:
                                         *      for (var j = 0; j < vertexBuffer.Count; j++)
                                         *      {
                                         *          fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:");
                                         *          fileWriter.WriteLine($"Hex : " + edResourceReader.ReadUInt32().ToString("X8"));
                                         *          fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}");
                                         *          fileWriter.WriteLine(Environment.NewLine);
                                         *      }
                                         *      break;
                                         */
                                    }

                                    //fileWriter.WriteLine($"End of Vertex Buffer index: {i}");

                                    //fileWriter.WriteLine(Environment.NewLine);
                                }
                            }
                    }
            }



            return(true);
        }
Esempio n. 6
0
        public override object Execute(List <string> args)
        {
            if (args.Count != 1)
            {
                return(false);
            }

            if (Definition.CollisionBspResource == null)
            {
                Console.WriteLine("ERROR: Collision geometry does not have a resource associated with it.");
                return(true);
            }

            var resourceContext    = new ResourceSerializationContext(CacheContext, Definition.CollisionBspResource);
            var resourceDefinition = CacheContext.Deserializer.Deserialize <StructureBspTagResources>(resourceContext);

            using (var resourceStream = new MemoryStream())
            {
                CacheContext.ExtractResource(Definition.CollisionBspResource, resourceStream);

                using (var reader = new EndianReader(resourceStream))
                {
                    foreach (var cbsp in resourceDefinition.CollisionBsps)
                    {
                        reader.BaseStream.Position = cbsp.Bsp3dNodes.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp3dNodes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp3dNode));
                            cbsp.Bsp3dNodes.Add((CollisionGeometry.Bsp3dNode)element);
                        }

                        reader.BaseStream.Position = cbsp.Planes.Address.Offset;
                        for (var i = 0; i < cbsp.Planes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane));
                            cbsp.Planes.Add((CollisionGeometry.Plane)element);
                        }

                        reader.BaseStream.Position = cbsp.Leaves.Address.Offset;
                        for (var i = 0; i < cbsp.Leaves.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf));
                            cbsp.Leaves.Add((CollisionGeometry.Leaf)element);
                        }

                        reader.BaseStream.Position = cbsp.Bsp2dReferences.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp2dReferences.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dReference));
                            cbsp.Bsp2dReferences.Add((CollisionGeometry.Bsp2dReference)element);
                        }

                        reader.BaseStream.Position = cbsp.Bsp2dNodes.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp2dNodes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dNode));
                            cbsp.Bsp2dNodes.Add((CollisionGeometry.Bsp2dNode)element);
                        }

                        reader.BaseStream.Position = cbsp.Surfaces.Address.Offset;
                        for (var i = 0; i < cbsp.Surfaces.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Surface));
                            cbsp.Surfaces.Add((CollisionGeometry.Surface)element);
                        }

                        reader.BaseStream.Position = cbsp.Edges.Address.Offset;
                        for (var i = 0; i < cbsp.Edges.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Edge));
                            cbsp.Edges.Add((CollisionGeometry.Edge)element);
                        }

                        reader.BaseStream.Position = cbsp.Vertices.Address.Offset;
                        for (var i = 0; i < cbsp.Vertices.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Vertex));
                            cbsp.Vertices.Add((CollisionGeometry.Vertex)element);
                        }
                    }

                    foreach (var cbsp in resourceDefinition.LargeCollisionBsps)
                    {
                        reader.BaseStream.Position = cbsp.Bsp3dNodes.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp3dNodes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Bsp3dNode));
                            cbsp.Bsp3dNodes.Add((StructureBspTagResources.LargeCollisionBspBlock.Bsp3dNode)element);
                        }

                        reader.BaseStream.Position = cbsp.Planes.Address.Offset;
                        for (var i = 0; i < cbsp.Planes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane));
                            cbsp.Planes.Add((CollisionGeometry.Plane)element);
                        }

                        reader.BaseStream.Position = cbsp.Leaves.Address.Offset;
                        for (var i = 0; i < cbsp.Leaves.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf));
                            cbsp.Leaves.Add((CollisionGeometry.Leaf)element);
                        }

                        reader.BaseStream.Position = cbsp.Bsp2dReferences.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp2dReferences.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Bsp2dReference));
                            cbsp.Bsp2dReferences.Add((StructureBspTagResources.LargeCollisionBspBlock.Bsp2dReference)element);
                        }

                        reader.BaseStream.Position = cbsp.Bsp2dNodes.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp2dNodes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Bsp2dNode));
                            cbsp.Bsp2dNodes.Add((StructureBspTagResources.LargeCollisionBspBlock.Bsp2dNode)element);
                        }

                        reader.BaseStream.Position = cbsp.Surfaces.Address.Offset;
                        for (var i = 0; i < cbsp.Surfaces.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Surface));
                            cbsp.Surfaces.Add((StructureBspTagResources.LargeCollisionBspBlock.Surface)element);
                        }

                        reader.BaseStream.Position = cbsp.Edges.Address.Offset;
                        for (var i = 0; i < cbsp.Edges.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Edge));
                            cbsp.Edges.Add((StructureBspTagResources.LargeCollisionBspBlock.Edge)element);
                        }

                        reader.BaseStream.Position = cbsp.Vertices.Address.Offset;
                        for (var i = 0; i < cbsp.Vertices.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Vertex));
                            cbsp.Vertices.Add((StructureBspTagResources.LargeCollisionBspBlock.Vertex)element);
                        }
                    }

                    foreach (var instance in resourceDefinition.InstancedGeometry)
                    {
                        reader.BaseStream.Position = instance.CollisionInfo.Bsp3dNodes.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Bsp3dNodes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp3dNode));
                            instance.CollisionInfo.Bsp3dNodes.Add((CollisionGeometry.Bsp3dNode)element);
                        }

                        reader.BaseStream.Position = instance.CollisionInfo.Planes.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Planes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane));
                            instance.CollisionInfo.Planes.Add((CollisionGeometry.Plane)element);
                        }

                        reader.BaseStream.Position = instance.CollisionInfo.Leaves.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Leaves.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf));
                            instance.CollisionInfo.Leaves.Add((CollisionGeometry.Leaf)element);
                        }

                        reader.BaseStream.Position = instance.CollisionInfo.Bsp2dReferences.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Bsp2dReferences.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dReference));
                            instance.CollisionInfo.Bsp2dReferences.Add((CollisionGeometry.Bsp2dReference)element);
                        }

                        reader.BaseStream.Position = instance.CollisionInfo.Bsp2dNodes.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Bsp2dNodes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dNode));
                            instance.CollisionInfo.Bsp2dNodes.Add((CollisionGeometry.Bsp2dNode)element);
                        }

                        reader.BaseStream.Position = instance.CollisionInfo.Surfaces.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Surfaces.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Surface));
                            instance.CollisionInfo.Surfaces.Add((CollisionGeometry.Surface)element);
                        }

                        reader.BaseStream.Position = instance.CollisionInfo.Edges.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Edges.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Edge));
                            instance.CollisionInfo.Edges.Add((CollisionGeometry.Edge)element);
                        }

                        reader.BaseStream.Position = instance.CollisionInfo.Vertices.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Vertices.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Vertex));
                            instance.CollisionInfo.Vertices.Add((CollisionGeometry.Vertex)element);
                        }

                        foreach (var cbsp in instance.CollisionGeometries)
                        {
                            reader.BaseStream.Position = cbsp.Bsp3dNodes.Address.Offset;
                            for (var i = 0; i < cbsp.Bsp3dNodes.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp3dNode));
                                cbsp.Bsp3dNodes.Add((CollisionGeometry.Bsp3dNode)element);
                            }

                            reader.BaseStream.Position = cbsp.Planes.Address.Offset;
                            for (var i = 0; i < cbsp.Planes.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane));
                                cbsp.Planes.Add((CollisionGeometry.Plane)element);
                            }

                            reader.BaseStream.Position = cbsp.Leaves.Address.Offset;
                            for (var i = 0; i < cbsp.Leaves.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf));
                                cbsp.Leaves.Add((CollisionGeometry.Leaf)element);
                            }

                            reader.BaseStream.Position = cbsp.Bsp2dReferences.Address.Offset;
                            for (var i = 0; i < cbsp.Bsp2dReferences.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dReference));
                                cbsp.Bsp2dReferences.Add((CollisionGeometry.Bsp2dReference)element);
                            }

                            reader.BaseStream.Position = cbsp.Bsp2dNodes.Address.Offset;
                            for (var i = 0; i < cbsp.Bsp2dNodes.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dNode));
                                cbsp.Bsp2dNodes.Add((CollisionGeometry.Bsp2dNode)element);
                            }

                            reader.BaseStream.Position = cbsp.Surfaces.Address.Offset;
                            for (var i = 0; i < cbsp.Surfaces.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Surface));
                                cbsp.Surfaces.Add((CollisionGeometry.Surface)element);
                            }

                            reader.BaseStream.Position = cbsp.Edges.Address.Offset;
                            for (var i = 0; i < cbsp.Edges.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Edge));
                                cbsp.Edges.Add((CollisionGeometry.Edge)element);
                            }

                            reader.BaseStream.Position = cbsp.Vertices.Address.Offset;
                            for (var i = 0; i < cbsp.Vertices.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Vertex));
                                cbsp.Vertices.Add((CollisionGeometry.Vertex)element);
                            }
                        }

                        for (var i = 0; i < instance.Unknown1.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.InstancedGeometryBlock.Unknown1Block));
                            instance.Unknown1.Add((StructureBspTagResources.InstancedGeometryBlock.Unknown1Block)element);
                        }

                        for (var i = 0; i < instance.Unknown2.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.InstancedGeometryBlock.Unknown2Block));
                            instance.Unknown2.Add((StructureBspTagResources.InstancedGeometryBlock.Unknown2Block)element);
                        }

                        for (var i = 0; i < instance.Unknown3.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.InstancedGeometryBlock.Unknown3Block));
                            instance.Unknown3.Add((StructureBspTagResources.InstancedGeometryBlock.Unknown3Block)element);
                        }

                        foreach (var collision in instance.BspPhysics)
                        {
                            for (var i = 0; i < collision.Data.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(byte));
                                collision.Data.Add(new StructureBspTagResources.CollisionBspPhysicsBlock.Datum {
                                    Value = (byte)element
                                });
                            }
                        }
                    }
                }

                var file = new FileInfo(args[0]);

                if (!file.Directory.Exists)
                {
                    file.Directory.Create();
                }

                using (var writer = new StreamWriter(file.Create()))
                {
                    var baseVertex = 0;

                    foreach (var bsp in resourceDefinition.CollisionBsps)
                    {
                        for (var i = 0; i < bsp.Vertices.Count; i++)
                        {
                            var vertex = bsp.Vertices[i];
                            writer.WriteLine($"v {vertex.Point.X} {vertex.Point.Z} {vertex.Point.Y}");
                        }

                        writer.WriteLine($"g bsp_surfaces_{resourceDefinition.CollisionBsps.IndexOf(bsp)}");

                        for (var i = 0; i < bsp.Surfaces.Count; i++)
                        {
                            var surface  = bsp.Surfaces[i];
                            var vertices = new HashSet <short>();
                            var edge     = bsp.Edges[surface.FirstEdge];

                            writer.Write("f");

                            while (true)
                            {
                                if (edge.LeftSurface == i)
                                {
                                    writer.Write($" {baseVertex + edge.StartVertex + 1}");

                                    if (edge.ForwardEdge == surface.FirstEdge)
                                    {
                                        break;
                                    }
                                    else
                                    {
                                        edge = bsp.Edges[edge.ForwardEdge];
                                    }
                                }
                                else if (edge.RightSurface == i)
                                {
                                    writer.Write($" {baseVertex + edge.EndVertex + 1}");

                                    if (edge.ReverseEdge == surface.FirstEdge)
                                    {
                                        break;
                                    }
                                    else
                                    {
                                        edge = bsp.Edges[edge.ReverseEdge];
                                    }
                                }
                            }

                            writer.WriteLine();
                        }

                        baseVertex += bsp.Vertices.Count;
                    }

                    foreach (var largeBsp in resourceDefinition.LargeCollisionBsps)
                    {
                        for (var i = 0; i < largeBsp.Vertices.Count; i++)
                        {
                            var vertex = largeBsp.Vertices[i];
                            writer.WriteLine($"v {vertex.Point.X} {vertex.Point.Z} {vertex.Point.Y}");
                        }

                        writer.WriteLine($"g large_bsp_surfaces_{resourceDefinition.LargeCollisionBsps.IndexOf(largeBsp)}");

                        for (var i = 0; i < largeBsp.Surfaces.Count; i++)
                        {
                            var surface  = largeBsp.Surfaces[i];
                            var vertices = new HashSet <short>();
                            var edge     = largeBsp.Edges[surface.FirstEdge];

                            writer.Write("f");

                            while (true)
                            {
                                if (edge.LeftSurface == i)
                                {
                                    writer.Write($" {baseVertex + edge.StartVertex + 1}");

                                    if (edge.ForwardEdge == surface.FirstEdge)
                                    {
                                        break;
                                    }
                                    else
                                    {
                                        edge = largeBsp.Edges[edge.ForwardEdge];
                                    }
                                }
                                else if (edge.RightSurface == i)
                                {
                                    writer.Write($" {baseVertex + edge.EndVertex + 1}");

                                    if (edge.ReverseEdge == surface.FirstEdge)
                                    {
                                        break;
                                    }
                                    else
                                    {
                                        edge = largeBsp.Edges[edge.ReverseEdge];
                                    }
                                }
                            }

                            writer.WriteLine();
                        }

                        baseVertex += largeBsp.Vertices.Count;
                    }

                    foreach (var instanceDef in Definition.InstancedGeometryInstances)
                    {
                        if (instanceDef.InstanceDefinition == -1)
                        {
                            continue;
                        }

                        var instance = resourceDefinition.InstancedGeometry[instanceDef.InstanceDefinition];

                        var instanceName = instanceDef.Name != StringId.Invalid ?
                                           CacheContext.GetString(instanceDef.Name) :
                                           $"instance_{instanceDef.InstanceDefinition}";

                        for (var i = 0; i < instance.CollisionInfo.Vertices.Count; i++)
                        {
                            var vertex = instance.CollisionInfo.Vertices[i];
                            var point  = Vector3.Transform(
                                new Vector3(vertex.Point.X, vertex.Point.Y, vertex.Point.Z),
                                new Matrix4x4(
                                    instanceDef.Matrix.m11, instanceDef.Matrix.m12, instanceDef.Matrix.m13, 0.0f,
                                    instanceDef.Matrix.m21, instanceDef.Matrix.m22, instanceDef.Matrix.m23, 0.0f,
                                    instanceDef.Matrix.m31, instanceDef.Matrix.m32, instanceDef.Matrix.m33, 0.0f,
                                    instanceDef.Matrix.m41, instanceDef.Matrix.m42, instanceDef.Matrix.m43, 0.0f));

                            writer.WriteLine($"v {point.X} {point.Z} {point.Y}");
                        }

                        writer.WriteLine($"g {instanceName}_main_surfaces");

                        for (var i = 0; i < instance.CollisionInfo.Surfaces.Count; i++)
                        {
                            var surface  = instance.CollisionInfo.Surfaces[i];
                            var vertices = new HashSet <short>();
                            var edge     = instance.CollisionInfo.Edges[surface.FirstEdge];

                            writer.Write("f");

                            while (true)
                            {
                                if (edge.LeftSurface == i)
                                {
                                    writer.Write($" {baseVertex + edge.StartVertex + 1}");

                                    if (edge.ForwardEdge == surface.FirstEdge)
                                    {
                                        break;
                                    }
                                    else
                                    {
                                        edge = instance.CollisionInfo.Edges[edge.ForwardEdge];
                                    }
                                }
                                else if (edge.RightSurface == i)
                                {
                                    writer.Write($" {baseVertex + edge.EndVertex + 1}");

                                    if (edge.ReverseEdge == surface.FirstEdge)
                                    {
                                        break;
                                    }
                                    else
                                    {
                                        edge = instance.CollisionInfo.Edges[edge.ReverseEdge];
                                    }
                                }
                            }

                            writer.WriteLine();
                        }

                        baseVertex += instance.CollisionInfo.Vertices.Count;

                        foreach (var bsp in instance.CollisionGeometries)
                        {
                            for (var i = 0; i < bsp.Vertices.Count; i++)
                            {
                                var vertex = bsp.Vertices[i];
                                writer.WriteLine($"v {vertex.Point.X} {vertex.Point.Z} {vertex.Point.Y}");
                            }

                            writer.WriteLine($"g {instanceName}_bsp_surfaces_{resourceDefinition.CollisionBsps.IndexOf(bsp)}");

                            for (var i = 0; i < bsp.Surfaces.Count; i++)
                            {
                                var surface  = bsp.Surfaces[i];
                                var vertices = new HashSet <short>();
                                var edge     = bsp.Edges[surface.FirstEdge];

                                writer.Write("f");

                                while (true)
                                {
                                    if (edge.LeftSurface == i)
                                    {
                                        writer.Write($" {baseVertex + edge.StartVertex + 1}");

                                        if (edge.ForwardEdge == surface.FirstEdge)
                                        {
                                            break;
                                        }
                                        else
                                        {
                                            edge = bsp.Edges[edge.ForwardEdge];
                                        }
                                    }
                                    else if (edge.RightSurface == i)
                                    {
                                        writer.Write($" {baseVertex + edge.EndVertex + 1}");

                                        if (edge.ReverseEdge == surface.FirstEdge)
                                        {
                                            break;
                                        }
                                        else
                                        {
                                            edge = bsp.Edges[edge.ReverseEdge];
                                        }
                                    }
                                }

                                writer.WriteLine();
                            }

                            baseVertex += bsp.Vertices.Count;
                        }
                    }
                }
            }

            return(true);
        }
Esempio n. 7
0
        public override object Execute(List <string> args)
        {
            if (Definition.PathfindingResource == null)
            {
                Console.WriteLine("ERROR: Pathfinding geometry does not have a resource associated with it.");
                return(true);
            }

            var resourceContext    = new ResourceSerializationContext(CacheContext, Definition.PathfindingResource);
            var resourceDefinition = CacheContext.Deserializer.Deserialize <StructureBspCacheFileTagResources>(resourceContext);

            using (var resourceStream = new MemoryStream())
                using (var reader = new EndianReader(resourceStream))
                    using (var writer = new EndianWriter(resourceStream))
                    {
                        CacheContext.ExtractResource(Definition.PathfindingResource, resourceStream);
                        var dataContext = new DataSerializationContext(reader, writer);

                        foreach (var pathfindingDatum in resourceDefinition.PathfindingData)
                        {
                            resourceStream.Position = pathfindingDatum.Sectors.Address.Offset;

                            for (var i = 0; i < pathfindingDatum.Sectors.Count; i++)
                            {
                                pathfindingDatum.Sectors.Add(
                                    CacheContext.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Sector>(dataContext));
                            }

                            resourceStream.Position = pathfindingDatum.Links.Address.Offset;

                            for (var i = 0; i < pathfindingDatum.Links.Count; i++)
                            {
                                pathfindingDatum.Links.Add(
                                    CacheContext.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Link>(dataContext));
                            }

                            resourceStream.Position = pathfindingDatum.PathfindingHints.Address.Offset;

                            for (var i = 0; i < pathfindingDatum.PathfindingHints.Count; i++)
                            {
                                pathfindingDatum.PathfindingHints.Add(
                                    CacheContext.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.PathfindingHint>(dataContext));
                            }

                            resourceStream.Position = pathfindingDatum.Vertices.Address.Offset;

                            for (var i = 0; i < pathfindingDatum.Vertices.Count; i++)
                            {
                                pathfindingDatum.Vertices.Add(
                                    CacheContext.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Vertex>(dataContext));
                            }

                            for (var i = 0; i < pathfindingDatum.PathfindingHints.Count; i++)
                            {
                                var hint = pathfindingDatum.PathfindingHints[i];

                                if (hint.HintType != JumpLink && hint.HintType != WallJumpLink)
                                {
                                    continue;
                                }

                                var hintverts = new List <short>();
                                var success   = false;

                                hintverts.Add((short)(hint.Data[1] & ushort.MaxValue));
                                hintverts.Add((short)((hint.Data[1] >> 16) & ushort.MaxValue));

                                if (hintverts[0] == -1 || hintverts[1] == -1)
                                {
                                    continue;
                                }

                                float hint_x = (pathfindingDatum.Vertices[hintverts[0]].Position.X + pathfindingDatum.Vertices[hintverts[1]].Position.X) / 2.0f;
                                float hint_y = (pathfindingDatum.Vertices[hintverts[0]].Position.Y + pathfindingDatum.Vertices[hintverts[1]].Position.Y) / 2.0f;
                                float hint_z = (pathfindingDatum.Vertices[hintverts[0]].Position.Z + pathfindingDatum.Vertices[hintverts[1]].Position.Z) / 2.0f;

                                var sectorlist       = new List <int>();
                                var backupsectorlist = new List <int>();

                                var zavelist       = new List <float>();
                                var backupzavelist = new List <float>();

                                for (var s = 0; s < pathfindingDatum.Sectors.Count; s++)
                                {
                                    var sector   = pathfindingDatum.Sectors[s];
                                    var vertices = new HashSet <short>();
                                    if (sector.FirstLink == -1)
                                    {
                                        continue;
                                    }
                                    var link = pathfindingDatum.Links[sector.FirstLink];

                                    while (true)
                                    {
                                        if (link.LeftSector == s)
                                        {
                                            vertices.Add(link.Vertex1);
                                            vertices.Add(link.Vertex2);
                                            if (link.ForwardLink == sector.FirstLink)
                                            {
                                                break;
                                            }
                                            else
                                            {
                                                link = pathfindingDatum.Links[link.ForwardLink];
                                            }
                                        }
                                        else if (link.RightSector == s)
                                        {
                                            vertices.Add(link.Vertex1);
                                            vertices.Add(link.Vertex2);
                                            if (link.ReverseLink == sector.FirstLink)
                                            {
                                                break;
                                            }
                                            else
                                            {
                                                link = pathfindingDatum.Links[link.ReverseLink];
                                            }
                                        }
                                    }

                                    var points = new List <RealPoint3d>();
                                    var xlist  = new List <float>();
                                    var ylist  = new List <float>();
                                    var zlist  = new List <float>();

                                    foreach (var vert in vertices)
                                    {
                                        points.Add(pathfindingDatum.Vertices[vert].Position);
                                        xlist.Add(pathfindingDatum.Vertices[vert].Position.X);
                                        ylist.Add(pathfindingDatum.Vertices[vert].Position.Y);
                                        zlist.Add(pathfindingDatum.Vertices[vert].Position.Z);
                                    }

                                    float xmin = xlist.Min();
                                    float xmax = xlist.Max();
                                    float ymin = ylist.Min();
                                    float ymax = ylist.Max();
                                    float zmin = zlist.Min();
                                    float zmax = zlist.Max();
                                    float zave = zlist.Average();

                                    bool pnpoly(List <RealPoint3d> polygon, RealPoint3d testPoint)
                                    {
                                        var result = false;

                                        for (int p = 0, j = polygon.Count - 1; p < polygon.Count(); j = p++)
                                        {
                                            if (polygon[p].Y < testPoint.Y && polygon[j].Y >= testPoint.Y || polygon[j].Y < testPoint.Y && polygon[p].Y >= testPoint.Y)
                                            {
                                                if (polygon[p].X + (testPoint.Y - polygon[p].Y) / (polygon[j].Y - polygon[p].Y) * (polygon[j].X - polygon[p].X) < testPoint.X)
                                                {
                                                    result = !result;
                                                }
                                            }
                                        }

                                        // TODO: maybe check Z?

                                        return(result);
                                    }

                                    if (pnpoly(points, new RealPoint3d(hint_x, hint_y, hint_z)))
                                    {
                                        sectorlist.Add(s);
                                        zavelist.Add(Math.Abs(hint_z - zave));
                                    }
                                    else if (xmin < hint_x && xmax > hint_x && ymin < hint_y && ymax > hint_y)
                                    {
                                        backupsectorlist.Add(s);
                                        backupzavelist.Add(Math.Abs(hint_z - zave));
                                    }
                                }

                                if (sectorlist.Count > 0)
                                {
                                    var s      = sectorlist[zavelist.IndexOf(zavelist.Min())];
                                    var hiword = (short)(hint.Data[3] >> 16);
                                    hint.Data[3] = hiword << 16 | s;
                                    success      = true;
                                }
                                else if (backupsectorlist.Count > 0)
                                {
                                    var s      = backupsectorlist[backupzavelist.IndexOf(backupzavelist.Min())];
                                    var hiword = (short)(hint.Data[3] >> 16);
                                    hint.Data[3] = hiword << 16 | s;
                                    success      = true;
                                }

                                if (!success)
                                {
                                    Console.WriteLine($"Pathfinding Jump Hint {i} sector not found!");
                                }
                            }

                            resourceStream.Position = pathfindingDatum.PathfindingHints.Address.Offset;

                            for (var i = 0; i < pathfindingDatum.PathfindingHints.Count; i++)
                            {
                                CacheContext.Serializer.Serialize(dataContext, pathfindingDatum.PathfindingHints[i]);
                            }

                            resourceStream.Position = 0;
                            CacheContext.ReplaceResource(Definition.PathfindingResource, resourceStream);
                        }
                    }

            return(true);
        }
Esempio n. 8
0
        public override object Execute(List <string> args)
        {
            // Deserialize the definition data
            var resourceContext = new ResourceSerializationContext(CacheContext, BSP.CollisionBspResource);
            var definition      = CacheContext.Deserializer.Deserialize <StructureBspTagResources>(resourceContext);

            // Extract the resource data
            var resourceDataStream = new MemoryStream();

            CacheContext.ExtractResource(BSP.CollisionBspResource, resourceDataStream);

            using (var reader = new EndianReader(resourceDataStream))
            {
                #region collision bsps

                foreach (var cbsp in definition.CollisionBsps)
                {
                    reader.BaseStream.Position = cbsp.Bsp3dNodes.Address.Offset;
                    for (var i = 0; i < cbsp.Bsp3dNodes.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp3dNode));
                        cbsp.Bsp3dNodes.Add((CollisionGeometry.Bsp3dNode)element);
                    }

                    reader.BaseStream.Position = cbsp.Planes.Address.Offset;
                    for (var i = 0; i < cbsp.Planes.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane));
                        cbsp.Planes.Add((CollisionGeometry.Plane)element);
                    }

                    reader.BaseStream.Position = cbsp.Leaves.Address.Offset;
                    for (var i = 0; i < cbsp.Leaves.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf));
                        cbsp.Leaves.Add((CollisionGeometry.Leaf)element);
                    }

                    reader.BaseStream.Position = cbsp.Bsp2dReferences.Address.Offset;
                    for (var i = 0; i < cbsp.Bsp2dReferences.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dReference));
                        cbsp.Bsp2dReferences.Add((CollisionGeometry.Bsp2dReference)element);
                    }

                    reader.BaseStream.Position = cbsp.Bsp2dNodes.Address.Offset;
                    for (var i = 0; i < cbsp.Bsp2dNodes.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dNode));
                        cbsp.Bsp2dNodes.Add((CollisionGeometry.Bsp2dNode)element);
                    }

                    reader.BaseStream.Position = cbsp.Surfaces.Address.Offset;
                    for (var i = 0; i < cbsp.Surfaces.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Surface));
                        cbsp.Surfaces.Add((CollisionGeometry.Surface)element);
                    }

                    reader.BaseStream.Position = cbsp.Edges.Address.Offset;
                    for (var i = 0; i < cbsp.Edges.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Edge));
                        cbsp.Edges.Add((CollisionGeometry.Edge)element);
                    }

                    reader.BaseStream.Position = cbsp.Vertices.Address.Offset;
                    for (var i = 0; i < cbsp.Vertices.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Vertex));
                        cbsp.Vertices.Add((CollisionGeometry.Vertex)element);
                    }
                }

                #endregion

                #region large collision bsps

                foreach (var cbsp in definition.LargeCollisionBsps)
                {
                    reader.BaseStream.Position = cbsp.Bsp3dNodes.Address.Offset;
                    for (var i = 0; i < cbsp.Bsp3dNodes.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Bsp3dNode));
                        cbsp.Bsp3dNodes.Add((StructureBspTagResources.LargeCollisionBspBlock.Bsp3dNode)element);
                    }

                    reader.BaseStream.Position = cbsp.Planes.Address.Offset;
                    for (var i = 0; i < cbsp.Planes.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane));
                        cbsp.Planes.Add((CollisionGeometry.Plane)element);
                    }

                    reader.BaseStream.Position = cbsp.Leaves.Address.Offset;
                    for (var i = 0; i < cbsp.Leaves.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf));
                        cbsp.Leaves.Add((CollisionGeometry.Leaf)element);
                    }

                    reader.BaseStream.Position = cbsp.Bsp2dReferences.Address.Offset;
                    for (var i = 0; i < cbsp.Bsp2dReferences.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Bsp2dReference));
                        cbsp.Bsp2dReferences.Add((StructureBspTagResources.LargeCollisionBspBlock.Bsp2dReference)element);
                    }

                    reader.BaseStream.Position = cbsp.Bsp2dNodes.Address.Offset;
                    for (var i = 0; i < cbsp.Bsp2dNodes.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Bsp2dNode));
                        cbsp.Bsp2dNodes.Add((StructureBspTagResources.LargeCollisionBspBlock.Bsp2dNode)element);
                    }

                    reader.BaseStream.Position = cbsp.Surfaces.Address.Offset;
                    for (var i = 0; i < cbsp.Surfaces.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Surface));
                        cbsp.Surfaces.Add((StructureBspTagResources.LargeCollisionBspBlock.Surface)element);
                    }

                    reader.BaseStream.Position = cbsp.Edges.Address.Offset;
                    for (var i = 0; i < cbsp.Edges.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Edge));
                        cbsp.Edges.Add((StructureBspTagResources.LargeCollisionBspBlock.Edge)element);
                    }

                    reader.BaseStream.Position = cbsp.Vertices.Address.Offset;
                    for (var i = 0; i < cbsp.Vertices.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Vertex));
                        cbsp.Vertices.Add((StructureBspTagResources.LargeCollisionBspBlock.Vertex)element);
                    }
                }

                #endregion

                #region compressions

                foreach (var instance in definition.InstancedGeometry)
                {
                    #region compression's resource data

                    reader.BaseStream.Position = instance.CollisionInfo.Bsp3dNodes.Address.Offset;
                    for (var i = 0; i < instance.CollisionInfo.Bsp3dNodes.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp3dNode));
                        instance.CollisionInfo.Bsp3dNodes.Add((CollisionGeometry.Bsp3dNode)element);
                    }

                    reader.BaseStream.Position = instance.CollisionInfo.Planes.Address.Offset;
                    for (var i = 0; i < instance.CollisionInfo.Planes.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane));
                        instance.CollisionInfo.Planes.Add((CollisionGeometry.Plane)element);
                    }

                    reader.BaseStream.Position = instance.CollisionInfo.Leaves.Address.Offset;
                    for (var i = 0; i < instance.CollisionInfo.Leaves.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf));
                        instance.CollisionInfo.Leaves.Add((CollisionGeometry.Leaf)element);
                    }

                    reader.BaseStream.Position = instance.CollisionInfo.Bsp2dReferences.Address.Offset;
                    for (var i = 0; i < instance.CollisionInfo.Bsp2dReferences.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dReference));
                        instance.CollisionInfo.Bsp2dReferences.Add((CollisionGeometry.Bsp2dReference)element);
                    }

                    reader.BaseStream.Position = instance.CollisionInfo.Bsp2dNodes.Address.Offset;
                    for (var i = 0; i < instance.CollisionInfo.Bsp2dNodes.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dNode));
                        instance.CollisionInfo.Bsp2dNodes.Add((CollisionGeometry.Bsp2dNode)element);
                    }

                    reader.BaseStream.Position = instance.CollisionInfo.Surfaces.Address.Offset;
                    for (var i = 0; i < instance.CollisionInfo.Surfaces.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Surface));
                        instance.CollisionInfo.Surfaces.Add((CollisionGeometry.Surface)element);
                    }

                    reader.BaseStream.Position = instance.CollisionInfo.Edges.Address.Offset;
                    for (var i = 0; i < instance.CollisionInfo.Edges.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Edge));
                        instance.CollisionInfo.Edges.Add((CollisionGeometry.Edge)element);
                    }

                    reader.BaseStream.Position = instance.CollisionInfo.Vertices.Address.Offset;
                    for (var i = 0; i < instance.CollisionInfo.Vertices.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Vertex));
                        instance.CollisionInfo.Vertices.Add((CollisionGeometry.Vertex)element);
                    }

                    #endregion

                    #region compression's other resource data

                    foreach (var cbsp in instance.CollisionGeometries)
                    {
                        reader.BaseStream.Position = cbsp.Bsp3dNodes.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp3dNodes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp3dNode));
                            cbsp.Bsp3dNodes.Add((CollisionGeometry.Bsp3dNode)element);
                        }

                        reader.BaseStream.Position = cbsp.Planes.Address.Offset;
                        for (var i = 0; i < cbsp.Planes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane));
                            cbsp.Planes.Add((CollisionGeometry.Plane)element);
                        }

                        reader.BaseStream.Position = cbsp.Leaves.Address.Offset;
                        for (var i = 0; i < cbsp.Leaves.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf));
                            cbsp.Leaves.Add((CollisionGeometry.Leaf)element);
                        }

                        reader.BaseStream.Position = cbsp.Bsp2dReferences.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp2dReferences.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dReference));
                            cbsp.Bsp2dReferences.Add((CollisionGeometry.Bsp2dReference)element);
                        }

                        reader.BaseStream.Position = cbsp.Bsp2dNodes.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp2dNodes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dNode));
                            cbsp.Bsp2dNodes.Add((CollisionGeometry.Bsp2dNode)element);
                        }

                        reader.BaseStream.Position = cbsp.Surfaces.Address.Offset;
                        for (var i = 0; i < cbsp.Surfaces.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Surface));
                            cbsp.Surfaces.Add((CollisionGeometry.Surface)element);
                        }

                        reader.BaseStream.Position = cbsp.Edges.Address.Offset;
                        for (var i = 0; i < cbsp.Edges.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Edge));
                            cbsp.Edges.Add((CollisionGeometry.Edge)element);
                        }

                        reader.BaseStream.Position = cbsp.Vertices.Address.Offset;
                        for (var i = 0; i < cbsp.Vertices.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Vertex));
                            cbsp.Vertices.Add((CollisionGeometry.Vertex)element);
                        }
                    }

                    #endregion

                    #region Unknown Data

                    for (var i = 0; i < instance.Unknown1.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.InstancedGeometryBlock.Unknown1Block));
                        instance.Unknown1.Add((StructureBspTagResources.InstancedGeometryBlock.Unknown1Block)element);
                    }

                    for (var i = 0; i < instance.Unknown2.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.InstancedGeometryBlock.Unknown2Block));
                        instance.Unknown2.Add((StructureBspTagResources.InstancedGeometryBlock.Unknown2Block)element);
                    }

                    for (var i = 0; i < instance.Unknown3.Count; i++)
                    {
                        var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.InstancedGeometryBlock.Unknown3Block));
                        instance.Unknown3.Add((StructureBspTagResources.InstancedGeometryBlock.Unknown3Block)element);
                    }

                    #endregion

                    #region compression's havok collision data

                    foreach (var collision in instance.BspPhysics)
                    {
                        for (var i = 0; i < collision.Data.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(byte));
                            collision.Data.Add(new StructureBspTagResources.CollisionBspPhysicsBlock.Datum {
                                Value = (byte)element
                            });
                        }
                    }

                    #endregion
                }

                #endregion
            }

            return(true);
        }
Esempio n. 9
0
        public override object Execute(List <string> args)
        {
            if (args.Count != 3)
            {
                return(false);
            }

            var variantName   = args[0];
            var fileType      = args[1].ToLower();
            var modelFileName = args[2];

            switch (fileType)
            {
            case "obj":
            case "amf":
            case "dae":
                break;

            default:
                throw new NotImplementedException(fileType);
            }

            //
            // Find the variant to extract
            //

            if (Definition.RenderModel == null)
            {
                Console.WriteLine("The model does not have a render model associated with it.");
                return(true);
            }


            var modelVariant = Definition.Variants.FirstOrDefault(v => (CacheContext.GetString(v.Name) ?? v.Name.ToString()) == variantName);

            if (modelVariant == null && Definition.Variants.Count > 0 && fileType != "dae")
            {
                Console.WriteLine("Unable to find variant \"{0}\"", variantName);
                Console.WriteLine("Use \"listvariants\" to list available variants.");
                return(true);
            }

            //
            // Deserialize the render model tag
            //

            RenderModel renderModel;

            using (var cacheStream = CacheContext.TagCacheFile.OpenRead())
            {
                renderModel = CacheContext.Deserialize <RenderModel>(cacheStream, Definition.RenderModel);
            }

            if (renderModel.Geometry.Resource == null)
            {
                Console.WriteLine("Render model does not have a resource associated with it");
                return(true);
            }

            //
            // Deserialize the resource definition
            //

            var resourceContext    = new ResourceSerializationContext(CacheContext, renderModel.Geometry.Resource);
            var resourceDefinition = CacheContext.Deserialize <RenderGeometryApiResourceDefinition>(resourceContext);

            using (var resourceStream = new MemoryStream())
            {
                //
                // Extract the resource data
                //

                CacheContext.ExtractResource(renderModel.Geometry.Resource, resourceStream);

                var modelFile = new FileInfo(modelFileName);

                if (!modelFile.Directory.Exists)
                {
                    modelFile.Directory.Create();
                }

                switch (fileType)
                {
                case "obj":
                    ExtractObj(modelFile, renderModel, modelVariant, resourceDefinition, resourceStream);
                    break;

                case "amf":
                    ExtractAmf(modelFile, renderModel, modelVariant, resourceDefinition, resourceStream);
                    break;

                case "dae":
                    ModelExtractor extractor = new ModelExtractor(CacheContext, renderModel);
                    extractor.ExtractRenderModel();
                    extractor.ExportCollada(modelFile);
                    break;

                default:
                    throw new NotImplementedException(fileType);
                }
            }

            Console.WriteLine("Done!");

            return(true);
        }
Esempio n. 10
0
        public override object Execute(List <string> args)
        {
            string variantName;
            string fileType;
            string modelFileName;

            if (args.Count == 2)
            {
                variantName   = "*";
                fileType      = args[0].ToLower();
                modelFileName = args[1];
            }
            else if (args.Count == 3)
            {
                variantName   = args[0];
                fileType      = args[1].ToLower();
                modelFileName = args[2];
            }
            else
            {
                return(false);
            }

            switch (fileType)
            {
            case "obj":
            case "dae":
                break;

            default:
                throw new NotImplementedException(fileType);
            }

            if (Definition.Geometry.Resource == null)
            {
                Console.WriteLine("Render model does not have a resource associated with it");
                return(true);
            }

            //
            // Deserialize the resource definition
            //

            var resourceContext    = new ResourceSerializationContext(CacheContext, Definition.Geometry.Resource);
            var resourceDefinition = CacheContext.Deserializer.Deserialize <RenderGeometryApiResourceDefinition>(resourceContext);

            using (var resourceStream = new MemoryStream())
            {
                //
                // Extract the resource data
                //

                CacheContext.ExtractResource(Definition.Geometry.Resource, resourceStream);

                var modelFile = new FileInfo(modelFileName);

                if (!modelFile.Directory.Exists)
                {
                    modelFile.Directory.Create();
                }

                ModelExtractor extractor = new ModelExtractor(CacheContext, Definition);
                extractor.ExtractRenderModel(variantName);

                switch (fileType)
                {
                case "obj":
                    return(extractor.ExportObject(modelFile));

                case "dae":
                    return(extractor.ExportCollada(modelFile));

                default:
                    throw new NotImplementedException(fileType);
                }
            }
        }
Esempio n. 11
0
        public override object Execute(List <string> args)
        {
            if (args.Count != 1)
            {
                return(false);
            }

            var outDirectory = args[0];

            if (!Directory.Exists(outDirectory))
            {
                Console.Write("Destination directory does not exist. Create it? [y/n] ");
                var answer = Console.ReadLine().ToLower();

                if (answer.Length == 0 || !(answer.StartsWith("y") || answer.StartsWith("n")))
                {
                    return(false);
                }

                if (answer.StartsWith("y"))
                {
                    Directory.CreateDirectory(outDirectory);
                }
                else
                {
                    return(false);
                }
            }


            var resource           = Definition.Resource;
            var resourceContext    = new ResourceSerializationContext(CacheContext, resource);
            var resourceDefinition = CacheContext.Deserializer.Deserialize <SoundResourceDefinition>(resourceContext);

            if (resourceDefinition.Data == null)
            {
                Console.WriteLine("Invalid sound definition");
                return(false);
            }

            var dataReference = resourceDefinition.Data;


            byte[] soundData          = new byte[dataReference.Size];
            var    resourceDataStream = new MemoryStream(soundData);

            CacheContext.ExtractResource(resource, resourceDataStream);

            for (int i = 0; i < Definition.PitchRanges.Count; i++)
            {
                var pitchRange = Definition.PitchRanges[i];
                for (int j = 0; j < pitchRange.Permutations.Count; j++)
                {
                    var permutation = pitchRange.Permutations[j];
                    var filename    = Tag.Index.ToString("X8") + "_" + i.ToString() + "_" + j.ToString();

                    byte[] permutationData = new byte[permutation.PermutationChunks[0].EncodedSize & 0x3FFFFFF];
                    Array.Copy(soundData, permutation.PermutationChunks[0].Offset, permutationData, 0, permutationData.Length);

                    switch (Definition.PlatformCodec.Compression)
                    {
                    case Compression.PCM:
                        filename += ".wav";
                        break;

                    case Compression.MP3:
                        filename += ".mp3";
                        break;

                    case Compression.FSB4:
                        filename += ".fsb";
                        break;
                    }

                    var outPath = Path.Combine(outDirectory, filename);

                    using (EndianWriter writer = new EndianWriter(new FileStream(outPath, FileMode.Create, FileAccess.Write, FileShare.None), EndianFormat.BigEndian))
                    {
                        var channelCount = Encoding.GetChannelCount(Definition.PlatformCodec.Encoding);
                        var sampleRate   = Definition.SampleRate.GetSampleRateHz();

                        switch (Definition.PlatformCodec.Compression)
                        {
                        case Compression.PCM:
                            WAVFile WAVfile = new WAVFile(permutationData, channelCount, sampleRate);
                            WAVfile.Write(writer);
                            break;

                        case Compression.MP3:
                        case Compression.FSB4:
                            writer.Write(permutationData);
                            break;
                        }
                    }
                }
            }
            Console.WriteLine("Done!");
            return(true);
        }
        public override object Execute(List <string> args)
        {
            if (args.Count != 2)
            {
                return(false);
            }

            var fileType = args[0];
            var fileName = args[1];

            if (fileType != "obj")
            {
                throw new NotSupportedException(fileType);
            }

            if (Definition.Geometry2.Resource == null)
            {
                Console.WriteLine("ERROR: Render geometry does not have a resource associated with it.");
                return(true);
            }

            //
            // Deserialize the resource definition
            //

            var resourceContext = new ResourceSerializationContext(CacheContext, Definition.Geometry2.Resource);
            var definition      = CacheContext.Deserializer.Deserialize <RenderGeometryApiResourceDefinition>(resourceContext);

            using (var resourceStream = new MemoryStream())
            {
                //
                // Extract the resource data
                //

                CacheContext.ExtractResource(Definition.Geometry2.Resource, resourceStream);

                var file = new FileInfo(fileName);

                if (!file.Directory.Exists)
                {
                    file.Directory.Create();
                }

                using (var objFile = new StreamWriter(file.Create()))
                {
                    var objExtractor = new ObjExtractor(objFile);

                    foreach (var cluster in Definition.Clusters)
                    {
                        var meshReader = new MeshReader(CacheContext.Version, Definition.Geometry2.Meshes[cluster.MeshIndex], definition);
                        objExtractor.ExtractMesh(meshReader, null, resourceStream);
                    }

                    foreach (var instance in Definition.InstancedGeometryInstances)
                    {
                        var vertexCompressor = new VertexCompressor(Definition.Geometry2.Compression[0]);
                        var meshReader       = new MeshReader(CacheContext.Version, Definition.Geometry2.Meshes[instance.InstanceDefinition], definition);
                        objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream);
                    }

                    objExtractor.Finish();
                }
            }

            Console.WriteLine("Done!");

            return(true);
        }
        public override object Execute(List <string> args)
        {
            if (args.Count != 0)
            {
                return(false);
            }

            if (Definition.CollisionBspResource == null)
            {
                Console.WriteLine("ERROR: Collision geometry does not have a resource associated with it.");
                return(true);
            }

            var resourceDefinition = CacheContext.Deserialize <StructureBspTagResources>(Definition.CollisionBspResource);

            using (var resourceStream = new MemoryStream())
            {
                CacheContext.ExtractResource(Definition.CollisionBspResource, resourceStream);

                using (var reader = new EndianReader(resourceStream))
                {
                    foreach (var cbsp in resourceDefinition.CollisionBsps)
                    {
                        reader.BaseStream.Position = cbsp.Bsp3dNodes.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp3dNodes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp3dNode));
                            cbsp.Bsp3dNodes.Add((CollisionGeometry.Bsp3dNode)element);
                        }

                        reader.BaseStream.Position = cbsp.Planes.Address.Offset;
                        for (var i = 0; i < cbsp.Planes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane));
                            cbsp.Planes.Add((CollisionGeometry.Plane)element);
                        }

                        reader.BaseStream.Position = cbsp.Leaves.Address.Offset;
                        for (var i = 0; i < cbsp.Leaves.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf));
                            cbsp.Leaves.Add((CollisionGeometry.Leaf)element);
                        }

                        reader.BaseStream.Position = cbsp.Bsp2dReferences.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp2dReferences.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dReference));
                            cbsp.Bsp2dReferences.Add((CollisionGeometry.Bsp2dReference)element);
                        }

                        reader.BaseStream.Position = cbsp.Bsp2dNodes.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp2dNodes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dNode));
                            cbsp.Bsp2dNodes.Add((CollisionGeometry.Bsp2dNode)element);
                        }

                        reader.BaseStream.Position = cbsp.Surfaces.Address.Offset;
                        for (var i = 0; i < cbsp.Surfaces.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Surface));
                            cbsp.Surfaces.Add((CollisionGeometry.Surface)element);
                        }

                        reader.BaseStream.Position = cbsp.Edges.Address.Offset;
                        for (var i = 0; i < cbsp.Edges.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Edge));
                            cbsp.Edges.Add((CollisionGeometry.Edge)element);
                        }

                        reader.BaseStream.Position = cbsp.Vertices.Address.Offset;
                        for (var i = 0; i < cbsp.Vertices.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Vertex));
                            cbsp.Vertices.Add((CollisionGeometry.Vertex)element);
                        }
                    }

                    foreach (var cbsp in resourceDefinition.LargeCollisionBsps)
                    {
                        reader.BaseStream.Position = cbsp.Bsp3dNodes.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp3dNodes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Bsp3dNode));
                            cbsp.Bsp3dNodes.Add((StructureBspTagResources.LargeCollisionBspBlock.Bsp3dNode)element);
                        }

                        reader.BaseStream.Position = cbsp.Planes.Address.Offset;
                        for (var i = 0; i < cbsp.Planes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane));
                            cbsp.Planes.Add((CollisionGeometry.Plane)element);
                        }

                        reader.BaseStream.Position = cbsp.Leaves.Address.Offset;
                        for (var i = 0; i < cbsp.Leaves.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf));
                            cbsp.Leaves.Add((CollisionGeometry.Leaf)element);
                        }

                        reader.BaseStream.Position = cbsp.Bsp2dReferences.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp2dReferences.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Bsp2dReference));
                            cbsp.Bsp2dReferences.Add((StructureBspTagResources.LargeCollisionBspBlock.Bsp2dReference)element);
                        }

                        reader.BaseStream.Position = cbsp.Bsp2dNodes.Address.Offset;
                        for (var i = 0; i < cbsp.Bsp2dNodes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Bsp2dNode));
                            cbsp.Bsp2dNodes.Add((StructureBspTagResources.LargeCollisionBspBlock.Bsp2dNode)element);
                        }

                        reader.BaseStream.Position = cbsp.Surfaces.Address.Offset;
                        for (var i = 0; i < cbsp.Surfaces.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Surface));
                            cbsp.Surfaces.Add((StructureBspTagResources.LargeCollisionBspBlock.Surface)element);
                        }

                        reader.BaseStream.Position = cbsp.Edges.Address.Offset;
                        for (var i = 0; i < cbsp.Edges.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Edge));
                            cbsp.Edges.Add((StructureBspTagResources.LargeCollisionBspBlock.Edge)element);
                        }

                        reader.BaseStream.Position = cbsp.Vertices.Address.Offset;
                        for (var i = 0; i < cbsp.Vertices.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Vertex));
                            cbsp.Vertices.Add((StructureBspTagResources.LargeCollisionBspBlock.Vertex)element);
                        }
                    }

                    foreach (var instance in resourceDefinition.InstancedGeometry)
                    {
                        reader.BaseStream.Position = instance.CollisionInfo.Bsp3dNodes.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Bsp3dNodes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp3dNode));
                            instance.CollisionInfo.Bsp3dNodes.Add((CollisionGeometry.Bsp3dNode)element);
                        }

                        reader.BaseStream.Position = instance.CollisionInfo.Planes.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Planes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane));
                            instance.CollisionInfo.Planes.Add((CollisionGeometry.Plane)element);
                        }

                        reader.BaseStream.Position = instance.CollisionInfo.Leaves.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Leaves.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf));
                            instance.CollisionInfo.Leaves.Add((CollisionGeometry.Leaf)element);
                        }

                        reader.BaseStream.Position = instance.CollisionInfo.Bsp2dReferences.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Bsp2dReferences.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dReference));
                            instance.CollisionInfo.Bsp2dReferences.Add((CollisionGeometry.Bsp2dReference)element);
                        }

                        reader.BaseStream.Position = instance.CollisionInfo.Bsp2dNodes.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Bsp2dNodes.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dNode));
                            instance.CollisionInfo.Bsp2dNodes.Add((CollisionGeometry.Bsp2dNode)element);
                        }

                        reader.BaseStream.Position = instance.CollisionInfo.Surfaces.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Surfaces.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Surface));
                            instance.CollisionInfo.Surfaces.Add((CollisionGeometry.Surface)element);
                        }

                        reader.BaseStream.Position = instance.CollisionInfo.Edges.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Edges.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Edge));
                            instance.CollisionInfo.Edges.Add((CollisionGeometry.Edge)element);
                        }

                        reader.BaseStream.Position = instance.CollisionInfo.Vertices.Address.Offset;
                        for (var i = 0; i < instance.CollisionInfo.Vertices.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Vertex));
                            instance.CollisionInfo.Vertices.Add((CollisionGeometry.Vertex)element);
                        }

                        foreach (var cbsp in instance.CollisionGeometries)
                        {
                            reader.BaseStream.Position = cbsp.Bsp3dNodes.Address.Offset;
                            for (var i = 0; i < cbsp.Bsp3dNodes.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp3dNode));
                                cbsp.Bsp3dNodes.Add((CollisionGeometry.Bsp3dNode)element);
                            }

                            reader.BaseStream.Position = cbsp.Planes.Address.Offset;
                            for (var i = 0; i < cbsp.Planes.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane));
                                cbsp.Planes.Add((CollisionGeometry.Plane)element);
                            }

                            reader.BaseStream.Position = cbsp.Leaves.Address.Offset;
                            for (var i = 0; i < cbsp.Leaves.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf));
                                cbsp.Leaves.Add((CollisionGeometry.Leaf)element);
                            }

                            reader.BaseStream.Position = cbsp.Bsp2dReferences.Address.Offset;
                            for (var i = 0; i < cbsp.Bsp2dReferences.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dReference));
                                cbsp.Bsp2dReferences.Add((CollisionGeometry.Bsp2dReference)element);
                            }

                            reader.BaseStream.Position = cbsp.Bsp2dNodes.Address.Offset;
                            for (var i = 0; i < cbsp.Bsp2dNodes.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dNode));
                                cbsp.Bsp2dNodes.Add((CollisionGeometry.Bsp2dNode)element);
                            }

                            reader.BaseStream.Position = cbsp.Surfaces.Address.Offset;
                            for (var i = 0; i < cbsp.Surfaces.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Surface));
                                cbsp.Surfaces.Add((CollisionGeometry.Surface)element);
                            }

                            reader.BaseStream.Position = cbsp.Edges.Address.Offset;
                            for (var i = 0; i < cbsp.Edges.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Edge));
                                cbsp.Edges.Add((CollisionGeometry.Edge)element);
                            }

                            reader.BaseStream.Position = cbsp.Vertices.Address.Offset;
                            for (var i = 0; i < cbsp.Vertices.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Vertex));
                                cbsp.Vertices.Add((CollisionGeometry.Vertex)element);
                            }
                        }

                        for (var i = 0; i < instance.Unknown1.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.InstancedGeometryBlock.Unknown1Block));
                            instance.Unknown1.Add((StructureBspTagResources.InstancedGeometryBlock.Unknown1Block)element);
                        }

                        for (var i = 0; i < instance.Unknown2.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.InstancedGeometryBlock.Unknown2Block));
                            instance.Unknown2.Add((StructureBspTagResources.InstancedGeometryBlock.Unknown2Block)element);
                        }

                        for (var i = 0; i < instance.Unknown3.Count; i++)
                        {
                            var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.InstancedGeometryBlock.Unknown3Block));
                            instance.Unknown3.Add((StructureBspTagResources.InstancedGeometryBlock.Unknown3Block)element);
                        }

                        foreach (var collision in instance.BspPhysics)
                        {
                            for (var i = 0; i < collision.Data.Count; i++)
                            {
                                var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(byte));
                                collision.Data.Add(new StructureBspTagResources.CollisionBspPhysicsBlock.Datum {
                                    Value = (byte)element
                                });
                            }
                        }
                    }
                }
            }

            Definition.TagResources = new List <ScenarioStructureBsp.TagResourcesBlock>
            {
                new ScenarioStructureBsp.TagResourcesBlock
                {
                    CollisionBsps = resourceDefinition.CollisionBsps.Select(
                        x => new CollisionGeometry
                    {
                        Bsp3dNodes      = x.Bsp3dNodes.Elements,
                        Planes          = x.Planes.Elements,
                        Leaves          = x.Leaves.Elements,
                        Bsp2dReferences = x.Bsp2dReferences.Elements,
                        Bsp2dNodes      = x.Bsp2dNodes.Elements,
                        Surfaces        = x.Surfaces.Elements,
                        Edges           = x.Edges.Elements,
                        Vertices        = x.Vertices.Elements
                    }).ToList(),

                    LargeCollisionBsps = resourceDefinition.LargeCollisionBsps.Select(
                        x => new ScenarioStructureBsp.TagResourcesBlock.LargeCollisionBspBlock
                    {
                        Bsp3dNodes      = x.Bsp3dNodes.Elements,
                        Planes          = x.Planes.Elements,
                        Leaves          = x.Leaves.Elements,
                        Bsp2dReferences = x.Bsp2dReferences.Elements,
                        Bsp2dNodes      = x.Bsp2dNodes.Elements,
                        Surfaces        = x.Surfaces.Elements,
                        Edges           = x.Edges.Elements,
                        Vertices        = x.Vertices.Elements
                    }).ToList(),

                    InstancedGeometry = resourceDefinition.InstancedGeometry.Select(
                        x => new ScenarioStructureBsp.TagResourcesBlock.InstancedGeometryBlock
                    {
                        Checksum             = x.Checksum,
                        BoundingSphereOffset = x.BoundingSphereOffset,
                        BoundingSphereRadius = x.BoundingSphereRadius,

                        CollisionInfo = new CollisionGeometry
                        {
                            Bsp3dNodes      = x.CollisionInfo.Bsp3dNodes.Elements,
                            Planes          = x.CollisionInfo.Planes.Elements,
                            Leaves          = x.CollisionInfo.Leaves.Elements,
                            Bsp2dReferences = x.CollisionInfo.Bsp2dReferences.Elements,
                            Bsp2dNodes      = x.CollisionInfo.Bsp2dNodes.Elements,
                            Surfaces        = x.CollisionInfo.Surfaces.Elements,
                            Edges           = x.CollisionInfo.Edges.Elements,
                            Vertices        = x.CollisionInfo.Vertices.Elements
                        },

                        CollisionGeometries = x.CollisionGeometries.Select(
                            y => new CollisionGeometry
                        {
                            Bsp3dNodes      = y.Bsp3dNodes.Elements,
                            Planes          = y.Planes.Elements,
                            Leaves          = y.Leaves.Elements,
                            Bsp2dReferences = y.Bsp2dReferences.Elements,
                            Bsp2dNodes      = y.Bsp2dNodes.Elements,
                            Surfaces        = y.Surfaces.Elements,
                            Edges           = y.Edges.Elements,
                            Vertices        = y.Vertices.Elements
                        }).ToList(),

                        BspPhysics = x.BspPhysics.Select(
                            y => new ScenarioStructureBsp.TagResourcesBlock.CollisionBspPhysicsBlock
                        {
                            Unused1              = y.Unused1,
                            Size                 = y.Size,
                            Count                = y.Count,
                            Address              = y.Address,
                            Unused2              = y.Unused2,
                            Offset               = y.Offset,
                            Unused3              = y.Unused3,
                            DataSize             = y.DataSize,
                            DataCapacityAndFlags = y.DataCapacityAndFlags,
                            DataBuildType        = y.DataBuildType,
                            Unused4              = y.Unused4,
                            Unused5              = y.Unused5,
                            Data                 = y.Data.Elements,
                            MoppBuildType        = y.MoppBuildType,
                            Unused6              = y.Unused6,
                            Unused7              = y.Unused7
                        }).ToList(),

                        Unknown1         = x.Unknown1.Elements,
                        Unknown2         = x.Unknown2.Elements,
                        Unknown3         = x.Unknown3.Elements,
                        MeshIndex        = x.MeshIndex,
                        CompressionIndex = x.CompressionIndex,
                        Unknown4         = x.Unknown4,
                        Unknown5         = x.Unknown5.Elements,
                        Unknown6         = x.Unknown6
                    }).ToList(),

                    HavokData = resourceDefinition.HavokData
                }
            };

            return(true);
        }
        public override object Execute(List <string> args)
        {
            if (args.Count != 1)
            {
                return(false);
            }

            if (Definition.PathfindingResource == null)
            {
                Console.WriteLine("ERROR: Pathfinding geometry does not have a resource associated with it.");
                return(true);
            }

            var resourceContext    = new ResourceSerializationContext(CacheContext, Definition.PathfindingResource);
            var resourceDefinition = CacheContext.Deserializer.Deserialize <StructureBspCacheFileTagResources>(resourceContext);

            using (var resourceStream = new MemoryStream())
                using (var reader = new EndianReader(resourceStream))
                {
                    CacheContext.ExtractResource(Definition.PathfindingResource, resourceStream);
                    var dataContext = new DataSerializationContext(reader);

                    foreach (var pathfindingDatum in resourceDefinition.PathfindingData)
                    {
                        resourceStream.Position = pathfindingDatum.Sectors.Address.Offset;

                        for (var i = 0; i < pathfindingDatum.Sectors.Count; i++)
                        {
                            pathfindingDatum.Sectors.Add(
                                CacheContext.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Sector>(dataContext));
                        }

                        resourceStream.Position = pathfindingDatum.Links.Address.Offset;

                        for (var i = 0; i < pathfindingDatum.Links.Count; i++)
                        {
                            pathfindingDatum.Links.Add(
                                CacheContext.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Link>(dataContext));
                        }

                        resourceStream.Position = pathfindingDatum.References.Address.Offset;

                        for (var i = 0; i < pathfindingDatum.References.Count; i++)
                        {
                            pathfindingDatum.References.Add(
                                CacheContext.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Reference>(dataContext));
                        }

                        resourceStream.Position = pathfindingDatum.Bsp2dNodes.Address.Offset;

                        for (var i = 0; i < pathfindingDatum.Bsp2dNodes.Count; i++)
                        {
                            pathfindingDatum.Bsp2dNodes.Add(
                                CacheContext.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Bsp2dNode>(dataContext));
                        }

                        resourceStream.Position = pathfindingDatum.PathfindingHints.Address.Offset;

                        for (var i = 0; i < pathfindingDatum.PathfindingHints.Count; i++)
                        {
                            pathfindingDatum.PathfindingHints.Add(
                                CacheContext.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.PathfindingHint>(dataContext));
                        }

                        resourceStream.Position = pathfindingDatum.Vertices.Address.Offset;

                        for (var i = 0; i < pathfindingDatum.Vertices.Count; i++)
                        {
                            pathfindingDatum.Vertices.Add(
                                CacheContext.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Vertex>(dataContext));
                        }

                        for (var objRefIdx = 0; objRefIdx < pathfindingDatum.ObjectReferences.Count; objRefIdx++)
                        {
                            for (var bspRefIdx = 0; bspRefIdx < pathfindingDatum.ObjectReferences[objRefIdx].Bsps.Count; bspRefIdx++)
                            {
                                var bspRef = pathfindingDatum.ObjectReferences[objRefIdx].Bsps[bspRefIdx];

                                resourceStream.Position = bspRef.Bsp2dRefs.Address.Offset;

                                for (var bsp2dRefIdx = 0; bsp2dRefIdx < bspRef.Bsp2dRefs.Count; bsp2dRefIdx++)
                                {
                                    bspRef.Bsp2dRefs.Add(
                                        CacheContext.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.ObjectReference.BspReference.Bsp2dRef>(dataContext));
                                }
                            }
                        }

                        resourceStream.Position = pathfindingDatum.InstancedGeometryReferences.Address.Offset;

                        for (var i = 0; i < pathfindingDatum.InstancedGeometryReferences.Count; i++)
                        {
                            pathfindingDatum.InstancedGeometryReferences.Add(
                                CacheContext.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.InstancedGeometryReference>(dataContext));
                        }

                        resourceStream.Position = pathfindingDatum.Doors.Address.Offset;

                        for (var i = 0; i < pathfindingDatum.Doors.Count; i++)
                        {
                            pathfindingDatum.Doors.Add(
                                CacheContext.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Door>(dataContext));
                        }
                    }
                }

            using (var writer = File.CreateText(args[0]))
            {
                foreach (var pathfinding in resourceDefinition.PathfindingData)
                {
                    writer.WriteLine("mtllib Blue.mtl");

                    foreach (ScenarioStructureBsp.PathfindingDatum.Vertex vertex in pathfinding.Vertices)
                    {
                        writer.WriteLine($"v {vertex.Position.X} {vertex.Position.Z} {vertex.Position.Y}");
                    }

                    writer.WriteLine("usemtl Blue");
                    writer.WriteLine("g JumpHints");

                    for (var i = 0; i < pathfinding.PathfindingHints.Count; i++)
                    {
                        var hint = pathfinding.PathfindingHints[i];
                        if (hint.HintType == ScenarioStructureBsp.PathfindingDatum.PathfindingHint.HintTypeValue.JumpLink)
                        {
                            int v2      = (hint.Data[0] >> 16) + 1;
                            int v1      = (hint.Data[0] & 0xFFFF) + 1;
                            int v4      = (hint.Data[1] >> 16) + 1;
                            int v3      = (hint.Data[1] & 0xFFFF) + 1;
                            int landing = hint.Data[3] & 0xFFFF;
                            writer.WriteLine($"o JumpHint {i}, Landing Sector {landing}");
                            writer.WriteLine($"f {v1} {v2} {v4} {v3}");
                        }
                    }

                    writer.WriteLine("usemtl White");
                    writer.WriteLine("g Sectors");

                    for (var i = 0; i < pathfinding.Sectors.Count; i++)
                    {
                        var sector   = pathfinding.Sectors[i];
                        var vertices = new HashSet <short>();
                        var link     = pathfinding.Links[sector.FirstLink];

                        writer.WriteLine($"o Sector {i}");
                        writer.Write("f");

                        while (true)
                        {
                            if (link.LeftSector == i)
                            {
                                writer.Write($" {link.Vertex1 + 1}");

                                if (link.ForwardLink == sector.FirstLink)
                                {
                                    break;
                                }
                                else
                                {
                                    link = pathfinding.Links[link.ForwardLink];
                                }
                            }
                            else if (link.RightSector == i)
                            {
                                writer.Write($" {link.Vertex2 + 1}");

                                if (link.ReverseLink == sector.FirstLink)
                                {
                                    break;
                                }
                                else
                                {
                                    link = pathfinding.Links[link.ReverseLink];
                                }
                            }
                        }

                        writer.WriteLine();
                    }
                }
            }

            return(true);
        }