Exemplo n.º 1
0
        public override void Save(Stream fileStream)
        {
            var writer = new BINAWriter(fileStream, Header);

            char[] WTXTMagic = { 'W', 'T', 'X', 'T' };
            writer.Write(WTXTMagic);
            writer.AddString($"mstName", $"{Name}");
            writer.Write(entries.Count);
            for (int i = 0; i < entries.Count; i++)
            {
                writer.AddString($"nameOffset{i}", $"{entries[i].Name}");
                writer.AddOffset($"textOffset{i}");
                writer.AddOffset($"placeholderOffset{i}");
            }
            for (int i = 0; i < entries.Count; i++)
            {
                writer.FillInOffset($"textOffset{i}", false);
                writer.WriteNullTerminatedStringUTF16(entries[i].Text);
            }
            for (int i = 0; i < entries.Count; i++)
            {
                writer.FillInOffset($"placeholderOffset{i}", false);
                writer.WriteNullTerminatedString(entries[i].Placeholder);
            }
            writer.FinishWrite(Header);
        }
Exemplo n.º 2
0
        public override void Save(Stream fileStream)
        {
            var writer = new BINAWriter(fileStream, Header);

            writer.AddOffset("VertexCountOffsetOffset");
            writer.Write(0); //PostFaceOffset (Not needed???)
            writer.FillInOffset("VertexCountOffsetOffset", false);
            writer.AddOffset("VertexCountOffset");
            writer.AddOffset("FaceCountOffset");

            writer.FillInOffset("VertexCountOffset", false);
            writer.Write(Vertices.Count);
            for (int i = 0; i < Vertices.Count; i++)
            {
                writer.Write(Vertices[i]);
            }

            writer.FillInOffset("FaceCountOffset", false);
            writer.Write(Faces.Count);
            for (int i = 0; i < Faces.Count; i++)
            {
                writer.Write(Faces[i].Vertex1);
                writer.Write(Faces[i].Vertex2);
                writer.Write(Faces[i].Vertex3);
                writer.WriteNulls(2);
                writer.Write(Faces[i].Flags);
            }

            writer.FinishWrite(Header);
        }
Exemplo n.º 3
0
        public override void Save(Stream fileStream)
        {
            // Header
            var writer = new BINAWriter(fileStream, Header);

            writer.AddString("gismOffset", Signature);
            writer.Write(UnknownBoolean1);
            writer.Write((uint)Gismos.Length);

            // Containers
            writer.AddOffset("containerOffset");
            writer.FillInOffset("containerOffset", false);

            // Container 1
            for (int i = 0; i < Gismos.Length; ++i)
            {
                var gismo = Gismos[i];
                writer.AddString($"fileNameOffset_{i}", gismo.FileName);
                writer.AddString($"fileNameOffset2_{i}", gismo.FileName);
                writer.AddString($"unknownOffset1_{i}", gismo.FileName); // TODO
                writer.Write(gismo.Unknown1);

                writer.Write(gismo.Unknown2);
                writer.Write(gismo.Unknown3);
                writer.Write((gismo.DoesAnimate) ? 1u : 0u);
                writer.AddOffset($"havokOffset_{i}");

                writer.Write((gismo.UnknownBoolean1) ? 1u : 0u);
                writer.AddOffset($"containerTwoOffset_{i}");
            }

            // Havok Array
            for (int i = 0; i < Gismos.Length; ++i)
            {
                writer.FillInOffset($"havokOffset_{i}", false);
                writer.WriteNulls(4); // TODO: Figure out what this is
                writer.AddString($"havokNameOffset_{i}", Gismos[i].HavokName);
            }

            // Container 2
            for (int i = 0; i < Gismos.Length; ++i)
            {
                var gismo = Gismos[i];
                writer.FillInOffset($"containerTwoOffset_{i}", false);

                writer.Write((gismo.UnknownBoolean2) ? 1u : 0u);
                writer.Write((gismo.UnknownBoolean3) ? 1u : 0u);

                writer.Write(gismo.Unknown5);
                writer.Write(gismo.Unknown6);
                writer.Write(gismo.Unknown7);

                writer.Write(gismo.Unknown8);
                writer.Write(gismo.RotationAmount);
                writer.Write(gismo.Unknown9);
            }

            writer.FinishWrite(Header);
        }
Exemplo n.º 4
0
            public void Write(BINAWriter writer, string prefix)
            {
                writer.Write(Nodes.Count);
                writer.Write(DataNodeIndices.Count);
                writer.AddOffset($"{prefix}nodesOffset", 8);
                writer.AddOffset($"{prefix}dataNodeIndicesOffset", 8);

                // Nodes
                writer.FillInOffsetLong($"{prefix}nodesOffset", true, false);
                foreach (var node in Nodes)
                {
                    node.Write(writer, this, prefix);
                }
            }
Exemplo n.º 5
0
        public override void Save(Stream fileStream)
        {
            // Header
            var header = new BINAv1Header();
            var writer = new BINAWriter(fileStream, header);

            writer.WriteSignature(Signature);

            // Texture
            writer.AddString("textureName", Texture);

            // Placeholders
            writer.Write((uint)Entries.Count);
            writer.AddOffset("placeholderEntriesPos");

            writer.FillInOffset("placeholderEntriesPos", false);
            for (int i = 0; i < Entries.Count; i++)
            {
                writer.AddString($"placeholderName{i}", Entries[i].Placeholder);
                writer.Write(Entries[i].X);
                writer.Write(Entries[i].Y);
                writer.Write(Entries[i].Width);
                writer.Write(Entries[i].Height);
            }

            writer.FinishWrite(header);
        }
Exemplo n.º 6
0
        public override void Save(Stream fileStream)
        {
            // Header
            var header = new BINAv1Header();
            var writer = new BINAWriter(fileStream, header);

            uint filesCount = 0;

            for (int i = 0; i < Types.Count; i++)
            {
                for (int c = 0; c < Types[i].Files.Count; c++)
                {
                    filesCount++;
                }
            }

            writer.Write(filesCount);
            writer.AddOffset("fileEntriesPos");
            writer.Write(Types.Count);
            writer.AddOffset("typeEntriesPos");

            writer.FillInOffset("typeEntriesPos", false);
            for (int i = 0; i < Types.Count; i++)
            {
                writer.AddString($"typeName{i}", Types[i].TypeName);
                writer.Write(Types[i].Files.Count);
                writer.AddOffset($"typeFilesOffset{i}");
            }

            writer.FillInOffset("fileEntriesPos", false);
            int objectNum = 0;

            for (int i = 0; i < Types.Count; i++)
            {
                writer.FillInOffset($"typeFilesOffset{i}", false);
                for (int f = 0; f < Types[i].Files.Count; f++)
                {
                    writer.AddString($"friendlyName{objectNum}", Types[i].Files[f].FriendlyName);
                    writer.AddString($"filePath{objectNum}", Types[i].Files[f].FilePath);
                    objectNum++;
                }
            }

            writer.FinishWrite(header);
        }
Exemplo n.º 7
0
        public override void Save(Stream fileStream)
        {
            // Header
            var header = new BINAv1Header();
            var writer = new BINAWriter(fileStream, header);

            writer.Write((uint)Files.Count);
            writer.AddOffset("fileEntriesPos");
            writer.Write((uint)Types.Count);
            writer.AddOffset("typeEntriesPos");

            // Types
            writer.FillInOffset("typeEntriesPos", false);
            for (int i = 0; i < Types.Count; i++)
            {
                writer.AddString($"typeName{i}", Types[i].TypeName);
                writer.Write(Types[i].FileCount);
                writer.AddOffset($"typeFilesOffset{i}");
            }

            // Files
            uint fileEntriesPos = (uint)writer.BaseStream.Position;

            writer.FillInOffset("fileEntriesPos", false);
            for (int i = 0; i < Files.Count; i++)
            {
                writer.AddString($"friendlyName{i}", Files[i].FriendlyName);
                writer.AddString($"filePath{i}", Files[i].FilePath);
            }

            // Fill-in type file offsets
            for (int i = 0; i < Types.Count; i++)
            {
                writer.FillInOffset($"typeFilesOffset{i}",
                                    (fileEntriesPos + (Types[i].FileStartIndex * 8U)),
                                    false, false);
            }

            writer.FinishWrite(header);
        }
Exemplo n.º 8
0
            public void Write(BINAWriter writer, string extension, uint id, int index)
            {
                writer.Write(id);
                writer.Write((ulong)Data.Length);
                writer.Write(0U);

                if (DataType == DataEntryTypes.NotHere)
                {
                    writer.Write(0UL);
                }
                else
                {
                    writer.AddOffset($"{extension}fileDataOffset{index}", 8);
                }

                writer.Write(0UL);
                writer.AddString($"{extension}extDataOffset{index}", extension, 8);
                writer.Write((ulong)DataType);
            }
Exemplo n.º 9
0
        public override void Save(Stream fileStream)
        {
            // Header
            var writer = new BINAWriter(fileStream, Header);

            writer.WriteSignature(Signature);
            writer.Write(1u); // TODO: Figure out what this value is.
            writer.Write(SoundEntries.Length);
            writer.AddOffset("soundEntriesOffset");

            // Data
            writer.FillInOffset("soundEntriesOffset", false);

            for (uint i = 0; i < SoundEntries.Length; ++i)
            {
                writer.Write(i);
                writer.AddString($"soundEntry_{i}", SoundEntries[i]);
            }

            writer.FinishWrite(Header);
        }
Exemplo n.º 10
0
        public override void Save(Stream fileStream)
        {
            //The file this produces needs the footer hex edited in some way to correct it (usually changing it to DBVBVB etc etc)
            var writer = new BINAWriter(fileStream, Header);

            writer.WriteSignature(Signature);
            writer.Write(1);   //Unknown 1
            writer.Write(Convert.ToInt64(SvShapes.Count));
            writer.Write(24L); //Unknown 2

            for (int i = 0; i < SvShapes.Count; i++)
            {
                writer.AddString($"ShapeName{i}", SvShapes[i].Name, 8u);
                writer.Write(SvShapes[i].Unknown1);
                writer.Write(SvShapes[i].Size);
                writer.Write(SvShapes[i].Position);
                writer.Write(SvShapes[i].Rotation);
                writer.Write(SvShapes[i].BoundingBox.Minimum);
                writer.Write(SvShapes[i].BoundingBox.Maximum);
                writer.Write(SvShapes[i].Unknown2);
                writer.Write(Convert.ToInt64(SvShapes[i].Sectors.Count));
                writer.AddOffset($"SectorsOffset{i}", 8u);
            }

            for (int i = 0; i < SvShapes.Count; i++)
            {
                writer.FillInOffset($"SectorsOffset{i}", false);
                for (int s = 0; s < SvShapes[i].Sectors.Count; s++)
                {
                    writer.Write(Convert.ToByte(SvShapes[i].Sectors[s].SectorIndex));
                    writer.Write(SvShapes[i].Sectors[s].Visible);
                }
            }

            writer.WriteNulls(0x30);
            writer.FinishWrite(Header);
        }
        public override void Save(Stream fileStream)
        {
            // Header
            var writer = new BINAWriter(fileStream, Header);

            writer.Write(0UL);
            writer.Write(0UL);

            writer.AddOffset("objectTableOffset", 8);
            writer.Write((ulong)Objects.Count);
            writer.Write((ulong)Objects.Count);
            writer.Write(0UL);

            // Objects
            writer.FillInOffsetLong("objectTableOffset", false, false);
            writer.AddOffsetTable("objectOffset", (uint)Objects.Count, 8);
            writer.FixPadding(16);

            for (int i = 0; i < Objects.Count; ++i)
            {
                var obj = Objects[i];
                writer.FillInOffsetLong($"objectOffset_{i}", false, false);
                WriteObject(writer, obj, i);
            }

            writer.FixPadding(16);

            // Object Parameters
            for (int i = 0; i < Objects.Count; ++i)
            {
                writer.FixPadding(16);
                WriteObjectParameters(writer, Objects[i], i);
            }

            writer.FinishWrite(Header);
        }
Exemplo n.º 12
0
        public override void Save(Stream fileStream)
        {
            var  writer           = new BINAWriter(fileStream, Header);
            var  typeCounts       = new Dictionary <string, int>();
            var  groupNameCounts  = new Dictionary <string, int>();
            var  groupTypeCounts  = new Dictionary <string, int>();
            uint stringParamCount = 0;

            // Header
            writer.WriteNulls(0xC);
            writer.WriteNullTerminatedString("test");
            writer.WriteNulls(0x1B);

            writer.Write(Objects.Count);
            writer.AddOffset("objectOffset");

            // TODO: Write group count
            writer.Write(groupNames.Count);
            writer.AddOffset("groupOffset");

            // Data
            writer.FillInOffset("objectOffset", false);
            for (int i = 0; i < Objects.Count; ++i)
            {
                WriteObject(i);
            }

            for (int i = 0; i < Objects.Count; ++i)
            {
                WriteObjectParams(i);
            }

            // Write Groups
            writer.FillInOffset("groupOffset", false);
            for (int i = 0; i < groupNameCounts.Count; ++i)
            {
                WriteGroup(i);
            }

            for (int i = 0; i < groupNameCounts.Count; ++i)
            {
                WriteGroupCounts(i);
            }

            // Write Footer
            writer.FinishWrite(Header);

            // Sub-Methods
            void WriteObject(int id)
            {
                // Object Entry
                var    obj  = Objects[id];
                string type = obj.ObjectType;

                if (!typeCounts.ContainsKey(type))
                {
                    typeCounts.Add(type, 1);
                }
                else
                {
                    ++typeCounts[type];
                }

                if (obj.CustomData["GroupName"].Data.ToString() != string.Empty)
                {
                    if (!groupNameCounts.ContainsKey(obj.CustomData["GroupName"].Data.ToString()))
                    {
                        groupNameCounts.Add(obj.CustomData["GroupName"].Data.ToString(), 1);
                    }
                    else
                    {
                        ++groupNameCounts[obj.CustomData["GroupName"].Data.ToString()];
                    }
                    Console.WriteLine(obj.CustomData["GroupName"].Data);
                }

                if (obj.CustomData["GroupType"].Data.ToString() != string.Empty)
                {
                    if (!groupTypeCounts.ContainsKey(obj.CustomData["GroupType"].Data.ToString()))
                    {
                        groupTypeCounts.Add(obj.CustomData["GroupType"].Data.ToString(), 1);
                    }
                    else
                    {
                        ++groupTypeCounts[obj.CustomData["GroupType"].Data.ToString()];
                    }
                    Console.WriteLine(obj.CustomData["GroupType"].Data);
                }

                string name = "";

                if (obj.CustomData.ContainsKey("Name"))
                {
                    name = (obj.CustomData["Name"].Data as string);
                }

                if (string.IsNullOrEmpty(name))
                {
                    writer.AddString($"nameOffset{id}", $"{type}{typeCounts[obj.ObjectType]}");
                }
                else
                {
                    writer.AddString($"nameOffset{id}", $"{name}");
                }

                writer.AddString($"typeOffset{id}", type);
                writer.WriteNulls(16);

                writer.Write(obj.Transform.Position);
                writer.Write(0);
                writer.Write(obj.Transform.Rotation);

                writer.Write(obj.Parameters.Count);
                writer.AddOffset($"paramOffset{id}");
            }

            void WriteGroup(int id)
            {
                writer.AddString($"groupNameOffset{id}", $"{groupNames[id]}");
                writer.AddString($"groupTypeOffset{id}", $"{groupTypes[id]}");
                writer.Write(3); //Should actually be the number of objects
                writer.AddOffset($"groupObjectCount{id}");
            }

            void WriteGroupCounts(int id)
            {
                writer.FillInOffset($"groupObjectCount{id}", false);
                //Should actually be the object IDs
                writer.Write(0); //Not sure how to properly write eight bytes rather than four...
                writer.Write(4);
            }

            void WriteObjectParams(int id)
            {
                var obj = Objects[id];

                writer.FillInOffset($"paramOffset{id}", false);

                foreach (var param in obj.Parameters)
                {
                    WriteParam(param);
                    writer.FixPadding(0x14); // TODO: Make sure this works right
                }
            }

            void WriteParam(SetObjectParam param)
            {
                Console.WriteLine(param.DataType);
                if (param.DataType == typeof(bool))
                {
                    writer.Write(0);
                    writer.Write(((bool)param.Data) ? 1 : 0);
                }
                else if (param.DataType == typeof(int))
                {
                    writer.Write(1);
                    writer.Write((int)param.Data);
                }
                else if (param.DataType == typeof(float))
                {
                    writer.Write(2);
                    writer.Write((float)param.Data);
                }
                else if (param.DataType == typeof(string))
                {
                    writer.Write(3);
                    writer.AddString($"offset{stringParamCount}", (string)param.Data);
                    writer.Write(1);

                    ++stringParamCount;
                }
                else if (param.DataType == typeof(Vector3))
                {
                    writer.Write(4);
                    writer.Write((Vector3)param.Data);
                }
                else if (param.DataType == typeof(uint))
                {
                    writer.Write(6);
                    writer.Write((uint)param.Data);
                }
                else
                {
                    Console.WriteLine(
                        "WARNING: '06 sets do not support object param type {0}!",
                        param.DataType);

                    writer.Write(0L);
                }
            }
        }
Exemplo n.º 13
0
        public override void Save(Stream fileStream)
        {
            // BINA Header
            var writer = new BINAWriter(fileStream, Header);
            var rand   = new Random();

            // Header
            writer.Write((byte)3); // TODO: Figure out what this is lol
            writer.Write((byte)Sheets.Count);
            writer.Write((byte)0);
            writer.Write((byte)0);

            writer.Write(0);
            writer.AddOffset("sheetsOffset", 8);

            // Sheets
            writer.FillInOffsetLong("sheetsOffset", false, false);
            for (int i = 0; i < Sheets.Count; ++i)
            {
                var sheet = Sheets[i];
                writer.AddString($"sheetNameOffset{i}", sheet.Name, 8);
                writer.Write((ulong)sheet.Cells.Count);
                writer.AddOffset($"cellsOffset{i}", 8);
            }

            // Cells
            for (int i = 0; i < Sheets.Count; ++i)
            {
                var sheet = Sheets[i];
                writer.FillInOffsetLong($"cellsOffset{i}", false, false);

                for (int i2 = 0; i2 < sheet.Cells.Count; ++i2)
                {
                    var cell = sheet.Cells[i2];
                    if (!cell.UUID.HasValue)
                    {
                        cell.UUID = (ulong)rand.Next();
                    }

                    writer.Write(cell.UUID.Value);
                    writer.AddString($"cellNameOffset{i}{i2}", cell.Name, 8);
                    writer.AddOffset($"secondEntryOffset{i}{i2}", 8);
                    writer.AddOffset($"dataOffset{i}{i2}", 8);
                }
            }

            // Data
            for (int i = 0; i < Sheets.Count; ++i)
            {
                var sheet = Sheets[i];
                for (int i2 = 0; i2 < sheet.Cells.Count; ++i2)
                {
                    var cell = sheet.Cells[i2];
                    writer.FillInOffsetLong($"dataOffset{i}{i2}", false, false);

                    var sb = new StringBuilder(cell.Data);
                    sb.Replace(NullReplaceChar, '\0');
                    sb.Replace("\r\n", "\n");
                    var bytes = Encoding.Unicode.GetBytes(sb.ToString());

                    writer.Write(bytes);
                    writer.Write((ushort)0);

                    writer.FixPadding(8);
                }
            }

            // Second Entries
            for (int i = 0; i < Sheets.Count; ++i)
            {
                var sheet = Sheets[i];
                for (int i2 = 0; i2 < sheet.Cells.Count; ++i2)
                {
                    var cell = sheet.Cells[i2];
                    writer.FillInOffsetLong($"secondEntryOffset{i}{i2}", false, false);
                    writer.AddString($"secondEntryNameOffset{i}{i2}", cell.Name, 8);

                    if (!string.IsNullOrEmpty(cell.TypeName))
                    {
                        writer.AddOffset($"typeOffset{i}{i2}", 8);
                    }
                    else
                    {
                        writer.Write(0UL);
                    }

                    writer.AddOffset($"layoutOffset{i}{i2}", 8);
                }
            }

            // Cell Types
            foreach (var type in Types)
            {
                // Fill-in Second Entry Type Offset
                var t = type.Value;
                for (int i = 0; i < Sheets.Count; ++i)
                {
                    var sheet = Sheets[i];
                    for (int i2 = 0; i2 < sheet.Cells.Count; ++i2)
                    {
                        var cell = sheet.Cells[i2];
                        if (string.IsNullOrEmpty(cell.TypeName) || cell.TypeName != type.Key)
                        {
                            continue;
                        }

                        writer.FillInOffsetLong($"typeOffset{i}{i2}", false, false);
                    }
                }

                // Offsets
                if (!string.IsNullOrEmpty(type.Key))
                {
                    writer.AddString($"typeName{type.Key}", type.Key, 8);
                }
                else
                {
                    writer.Write(0UL);
                }

                if (!string.IsNullOrEmpty(t.Namespace))
                {
                    writer.AddString($"typeNamespace{type.Key}", t.Namespace, 8);
                }
                else
                {
                    writer.Write(0UL);
                }

                WriteOptOffset($"typeUnknownFloat1Offset{type.Key}", t.UnknownFloat1);
                WriteOptOffset($"typeUnknownFloat2Offset{type.Key}", t.UnknownFloat2);
                WriteOptOffset($"typeUnknownFloat3Offset{type.Key}", t.UnknownFloat3);
                WriteOptOffset($"typeUnknownInt1Offset{type.Key}", t.UnknownInt1);
                WriteOptOffset($"typeUnknownInt2Offset{type.Key}", t.UnknownInt2);
                writer.Write(0UL); // unknownOffset1

                WriteOptOffset($"typeUnknownULong2Offset{type.Key}", t.UnknownULong2);
                writer.Write(0UL); // unknownOffset2
                writer.Write(0UL); // unknownOffset3
                writer.Write(0UL); // unknownOffset4

                WriteOptOffset($"typeUnknownULong1Offset{type.Key}", t.UnknownULong1);
                writer.Write(0UL); // unknownOffset5

                // UnknownFloat1
                if (t.UnknownFloat1.HasValue)
                {
                    writer.FillInOffsetLong($"typeUnknownFloat1Offset{type.Key}", false, false);
                    writer.Write(t.UnknownFloat1.Value);
                    writer.Write(0);
                }

                // UnknownFloat2
                if (t.UnknownFloat2.HasValue)
                {
                    writer.FillInOffsetLong($"typeUnknownFloat2Offset{type.Key}", false, false);
                    writer.Write(t.UnknownFloat2.Value);
                    writer.Write(0);
                }

                // UnknownFloat3
                if (t.UnknownFloat3.HasValue)
                {
                    writer.FillInOffsetLong($"typeUnknownFloat3Offset{type.Key}", false, false);
                    writer.Write(t.UnknownFloat3.Value);
                    writer.Write(0);
                }

                // UnknownInt1
                if (t.UnknownInt1.HasValue)
                {
                    writer.FillInOffsetLong($"typeUnknownInt1Offset{type.Key}", false, false);
                    writer.Write(t.UnknownInt1.Value);
                    writer.Write(0);
                }

                // UnknownInt2
                if (t.UnknownInt2.HasValue)
                {
                    writer.FillInOffsetLong($"typeUnknownInt2Offset{type.Key}", false, false);
                    writer.Write(t.UnknownInt2.Value);
                    writer.Write(0);
                }

                // UnknownULong1
                if (t.UnknownULong1.HasValue)
                {
                    writer.FillInOffsetLong($"typeUnknownULong1Offset{type.Key}", false, false);
                    writer.Write(t.UnknownULong1.Value);
                }

                // UnknownULong2
                if (t.UnknownULong2.HasValue)
                {
                    writer.FillInOffsetLong($"typeUnknownULong2Offset{type.Key}", false, false);
                    writer.Write(t.UnknownULong2.Value);
                }
            }

            // Layouts
            for (int i = 0; i < Layouts.Count; ++i)
            {
                writer.FixPadding(8);

                // Fill-In Cell Offsets
                var cat = Layouts[i];
                for (int sheetIndex = 0; sheetIndex < Sheets.Count; ++sheetIndex)
                {
                    var sheet = Sheets[sheetIndex];
                    for (int i2 = 0; i2 < sheet.Cells.Count; ++i2)
                    {
                        var cell = sheet.Cells[i2];
                        if (cell.LayoutIndex != i)
                        {
                            continue;
                        }

                        writer.FillInOffsetLong($"layoutOffset{sheetIndex}{i2}", false, false);
                    }
                }

                // Write Layout
                if (!string.IsNullOrEmpty(cat.Name))
                {
                    writer.AddString($"layoutName{i}", cat.Name, 8);
                }
                else
                {
                    writer.Write(0UL);
                }

                WriteOptOffset($"catUnknownData1{i}", cat.UnknownData1);
                WriteOptOffset($"catUnknownData2{i}", cat.UnknownData2);
                WriteOptOffset($"catUnknownData3{i}", cat.UnknownData3);
                WriteOptOffset($"catUnknownData4{i}", cat.UnknownData4);
                WriteOptOffset($"catUnknownData5{i}", cat.UnknownData5);
                WriteOptOffset($"catUnknownData6{i}", cat.UnknownData6);
                WriteOptOffset($"catUnknownData7{i}", cat.UnknownData7);
                writer.Write(cat.UnknownData8);

                // UnknownData1
                if (cat.UnknownData1.HasValue)
                {
                    writer.FixPadding(8);
                    writer.FillInOffsetLong($"catUnknownData1{i}", false, false);
                    writer.Write(cat.UnknownData1.Value);
                }

                // UnknownData2
                if (cat.UnknownData2.HasValue)
                {
                    writer.FixPadding(8);
                    writer.FillInOffsetLong($"catUnknownData2{i}", false, false);
                    writer.Write(cat.UnknownData2.Value);
                }

                // UnknownData3
                if (cat.UnknownData3.HasValue)
                {
                    writer.FixPadding(8);
                    writer.FillInOffsetLong($"catUnknownData3{i}", false, false);
                    writer.Write(cat.UnknownData3.Value);
                }

                // UnknownData4
                if (cat.UnknownData4.HasValue)
                {
                    writer.FixPadding(8);
                    writer.FillInOffsetLong($"catUnknownData4{i}", false, false);
                    writer.Write(cat.UnknownData4.Value);
                }

                // UnknownData5
                if (cat.UnknownData5.HasValue)
                {
                    writer.FixPadding(8);
                    writer.FillInOffsetLong($"catUnknownData5{i}", false, false);
                    writer.Write(cat.UnknownData5.Value);
                }

                // UnknownData6
                if (cat.UnknownData6.HasValue)
                {
                    writer.FixPadding(8);
                    writer.FillInOffsetLong($"catUnknownData6{i}", false, false);
                    writer.Write(cat.UnknownData6.Value);
                }

                // UnknownData7
                if (cat.UnknownData7.HasValue)
                {
                    writer.FixPadding(8);
                    writer.FillInOffsetLong($"catUnknownData7{i}", false, false);
                    writer.Write(cat.UnknownData7.Value);
                }
            }

            // Footer
            writer.FinishWrite(Header);

            // Sub-Methods
            void WriteOptOffset <T>(string offsetName, T?value)
                where T : struct
            {
                if (value.HasValue)
                {
                    writer.AddOffset(offsetName, 8);
                }
                else
                {
                    writer.Write(0UL);
                }
            }
        }
        protected void WriteObjectParameters(BINAWriter writer,
                                             SetObject obj, int objID)
        {
            uint arrIndex = 0, strIndex = 0;
            uint paramStartPos = (uint)writer.BaseStream.Position;

            writer.FillInOffsetLong($"objParamsOffset{objID}", false, false);

            // Write Normal Parameters
            foreach (var param in obj.Parameters)
            {
                WriteParameter(param);
            }

            // Padding
            uint rawLength = obj.GetCustomDataValue <uint>("RawByteLength");
            uint len       = (uint)(writer.BaseStream.Position - paramStartPos);

            if (rawLength > len)
            {
                writer.WriteNulls(rawLength - len);
            }

            // Write Arrays
            if (arrIndex < 1)
            {
                return; // Don't bother if there's not even any arrays
            }
            writer.FixPadding(8);
            arrIndex = 0;
            foreach (var param in obj.Parameters)
            {
                WriteArray(param);
            }

            // Sub-Methods
            void WriteParameter(SetObjectParam param)
            {
                FixPadding(writer, param.DataType);

                // Special Param Types
                if (param is SetObjectParamGroup group)
                {
                    foreach (var p in group.Parameters)
                    {
                        WriteParameter(p);
                    }

                    writer.FixPadding(group.Padding ?? 16);
                    return;
                }
                else if (param.DataType == typeof(ObjectReference[]))
                {
                    var   arr       = (param.Data as ObjectReference[]);
                    ulong arrLength = (ulong)arr.LongLength;

                    if (arrLength < 1)
                    {
                        writer.WriteNulls(24);
                        return;
                    }

                    writer.AddOffset($"obj{objID}ArrOffset{arrIndex}", 8);
                    writer.Write(arrLength);
                    writer.Write(arrLength);
                    ++arrIndex;
                    return;
                }
                else if (param.DataType == typeof(ObjectReference))
                {
                    var reference = (param.Data as ObjectReference);
                    if (reference == null)
                    {
                        writer.Write(0U);
                        return;
                    }

                    reference.Write(writer);
                    return;
                }
                else if (param.DataType == typeof(string))
                {
                    string str = (param.Data as string);
                    if (string.IsNullOrEmpty(str))
                    {
                        writer.Write(0UL);
                        writer.Write(0UL);
                        return;
                    }

                    writer.AddString($"obj{objID}StrOffset{strIndex}", str, 8);
                    writer.Write(0UL);
                    ++strIndex;
                    return;
                }

                // Data
                writer.WriteByType(param.DataType, param.Data);

                // Post-Param Padding
                if (param.DataType == typeof(Vector3))
                {
                    writer.Write(0U);
                }
            }

            void WriteArray(SetObjectParam param)
            {
                // Groups
                if (param is SetObjectParamGroup group)
                {
                    foreach (var p in group.Parameters)
                    {
                        WriteArray(p);
                    }

                    return;
                }

                // Array Values
                if (param.DataType == typeof(ObjectReference[]))
                {
                    var arr = (param.Data as ObjectReference[]);
                    if (arr == null || arr.Length < 1)
                    {
                        return;
                    }

                    writer.FillInOffsetLong($"obj{objID}ArrOffset{arrIndex}", false, false);
                    for (uint i = 0; i < arr.Length; ++i)
                    {
                        if (arr[i] == null)
                        {
                            writer.Write(0U);
                        }
                        else
                        {
                            arr[i].Write(writer);
                        }
                    }

                    ++arrIndex;
                }
            }
        }
Exemplo n.º 15
0
        public override void Save(Stream fileStream)
        {
            var  writer           = new BINAWriter(fileStream, Header);
            var  typeCounts       = new Dictionary <string, int>();
            uint stringParamCount = 0;

            // Header
            writer.WriteNulls(0xC);
            writer.WriteNullTerminatedString("test");
            writer.WriteNulls(0x1B);

            writer.Write(Objects.Count);
            writer.AddOffset("objectOffset");

            // TODO: Write group count
            writer.Write(0);
            writer.Write(0);

            // Data
            writer.FillInOffset("objectOffset", false);
            for (int i = 0; i < Objects.Count; ++i)
            {
                WriteObject(i);
            }

            for (int i = 0; i < Objects.Count; ++i)
            {
                WriteObjectParams(i);
            }

            // Write Groups
            // TODO: Write groups properly

            // Write Footer
            writer.FinishWrite(Header);

            // Sub-Methods
            void WriteObject(int id)
            {
                // Object Entry
                var    obj  = Objects[id];
                string type = obj.ObjectType;

                if (!typeCounts.ContainsKey(type))
                {
                    typeCounts.Add(type, 1);
                }
                else
                {
                    ++typeCounts[type];
                }

                writer.AddString($"nameOffset{id}", $"{type}{typeCounts[obj.ObjectType]}");
                writer.AddString($"typeOffset{id}", type);
                writer.WriteNulls(16);

                writer.Write(obj.Transform.Position);
                writer.Write(0);
                writer.Write(obj.Transform.Rotation);

                writer.Write(obj.Parameters.Count);
                writer.AddOffset($"paramOffset{id}");
            }

            void WriteObjectParams(int id)
            {
                var obj = Objects[id];

                writer.FillInOffset($"paramOffset{id}", false);

                foreach (var param in obj.Parameters)
                {
                    WriteParam(param);
                    writer.FixPadding(0x14); // TODO: Make sure this works right
                }
            }

            void WriteParam(SetObjectParam param)
            {
                if (param.DataType == typeof(bool))
                {
                    writer.Write(0);
                    writer.Write(((bool)param.Data) ? 1 : 0);
                }
                else if (param.DataType == typeof(int))
                {
                    writer.Write(1);
                    writer.Write((int)param.Data);
                }
                else if (param.DataType == typeof(float))
                {
                    writer.Write(2);
                    writer.Write((float)param.Data);
                }
                else if (param.DataType == typeof(string))
                {
                    writer.Write(3);
                    writer.AddString($"offset{stringParamCount}", (string)param.Data);
                    writer.Write(1);

                    ++stringParamCount;
                }
                else if (param.DataType == typeof(Vector3))
                {
                    writer.Write(4);
                    writer.Write((Vector3)param.Data);
                }
                else if (param.DataType == typeof(uint))
                {
                    writer.Write(6);
                    writer.Write((uint)param.Data);
                }
                else
                {
                    Console.WriteLine(
                        "WARNING: '06 sets do not support object param type {0}!",
                        param.DataType);

                    writer.Write(0L);
                }
            }
        }
        protected void WriteObject(BINAWriter writer, SetObject obj, int objID)
        {
            writer.Write(0UL);

            // Object Type
            writer.AddString($"objTypeOffset{objID}", obj.ObjectType, 8);

            // Object Name
            string name = "";

            if (obj.CustomData.ContainsKey("Name"))
            {
                name = (obj.CustomData["Name"].Data as string);
            }

            if (string.IsNullOrEmpty(name))
            {
                name = $"{obj.ObjectType}{objID}";
            }

            writer.AddString($"objNameOffset{objID}", name, 8);

            // Object Entry
            writer.Write((ushort)obj.ObjectID);
            writer.Write((obj.CustomData.ContainsKey("GroupID")) ?
                         (ushort)obj.CustomData["GroupID"].Data :
                         obj.GetCustomDataValue <ushort>("Unknown1"));

            writer.Write(obj.GetCustomDataValue <ushort>("ParentID"));
            writer.Write((obj.CustomData.ContainsKey("ParentGroupID")) ?
                         (ushort)obj.CustomData["ParentGroupID"].Data :
                         obj.GetCustomDataValue <ushort>("ParentUnknown1"));

            writer.Write(obj.Transform.Position);
            writer.Write(obj.Transform.Rotation.ToEulerAngles(true));

            writer.Write((obj.CustomData.ContainsKey("ChildPosOffset")) ?
                         (Vector3)obj.CustomData["ChildPosOffset"].Data :
                         obj.Transform.Position);

            writer.Write((obj.CustomData.ContainsKey("ChildRotOffset")) ?
                         (Vector3)obj.CustomData["ChildRotOffset"].Data :
                         obj.Transform.Rotation.ToEulerAngles(true));

            // Extra Parameter Entries
            uint extraParamCounts = (uint)obj.CustomData.Count;

            if (obj.CustomData.ContainsKey("Name"))
            {
                extraParamCounts -= 1;
            }

            if (obj.CustomData.ContainsKey("RangeOut"))
            {
                extraParamCounts -= 1;
            }

            if (obj.CustomData.ContainsKey("GroupID") ||
                obj.CustomData.ContainsKey("Unknown1"))
            {
                extraParamCounts -= 1;
            }

            if (obj.CustomData.ContainsKey("ParentID"))
            {
                extraParamCounts -= 1;
            }

            if (obj.CustomData.ContainsKey("ParentGroupID") ||
                obj.CustomData.ContainsKey("ParentUnknown1"))
            {
                extraParamCounts -= 1;
            }

            if (obj.CustomData.ContainsKey("ChildPosOffset"))
            {
                extraParamCounts -= 1;
            }

            if (obj.CustomData.ContainsKey("ChildRotOffset"))
            {
                extraParamCounts -= 1;
            }

            if (obj.CustomData.ContainsKey("RawByteLength"))
            {
                extraParamCounts -= 1;
            }

            writer.AddOffset($"extraParamsOffset{objID}", 8);
            writer.Write((ulong)extraParamCounts); // TODO
            writer.Write((ulong)extraParamCounts); // TODO
            writer.Write(0UL);
            writer.AddOffset($"objParamsOffset{objID}", 8);
            writer.FixPadding(16);

            writer.FillInOffsetLong($"extraParamsOffset{objID}", false, false);
            writer.AddOffsetTable($"extraParamOffset{objID}", extraParamCounts, 8);
            writer.FixPadding(16); // TODO: Make sure this is correct

            int i = -1;

            foreach (var customData in obj.CustomData)
            {
                if (customData.Key == "Name" || customData.Key == "GroupID" ||
                    customData.Key == "Unknown1" || customData.Key == "ParentID" ||
                    customData.Key == "ParentGroupID" || customData.Key == "ParentUnknown1" ||
                    customData.Key == "RangeOut" || customData.Key == "ChildPosOffset" ||
                    customData.Key == "ChildRotOffset" || customData.Key == "RawByteLength")
                {
                    continue;
                }

                writer.FillInOffsetLong(
                    $"extraParamOffset{objID}_{++i}", false, false);

                writer.Write(0UL);
                writer.AddString($"extraParamNameOffset{objID}{i}",
                                 (customData.Key == "RangeIn") ? "RangeSpawning" : customData.Key, 8);

                if (!WriteExtraParamLength(writer, customData))
                {
                    writer.Write(0);
                    Console.WriteLine(
                        $"WARNING: CustomData {customData.Key} skipped; Unknown Type!");
                }

                writer.AddOffset($"extraParamDataOffset{objID}{i}", 8);
            }

            // Extra Parameter Data
            foreach (var customData in obj.CustomData)
            {
                if (customData.Key == "Name" || customData.Key == "GroupID" ||
                    customData.Key == "Unknown1" || customData.Key == "ParentID" ||
                    customData.Key == "ParentGroupID" || customData.Key == "ParentUnknown1" ||
                    customData.Key == "RangeOut" || customData.Key == "ChildPosOffset" ||
                    customData.Key == "ChildRotOffset" || customData.Key == "RawByteLength")
                {
                    continue;
                }

                writer.FillInOffsetLong(
                    $"extraParamDataOffset{objID}{i}", false, false);

                if (!WriteExtraParamData(writer, obj, customData))
                {
                    writer.Write(0UL);
                }
            }
        }
        protected void WriteNodeTree(BINAWriter writer,
                                     NodeTree tree, string prefix)
        {
            writer.Write(tree.Nodes.Count);
            writer.Write(tree.DataNodeCount);
            writer.AddOffset($"{prefix}nodesOffset", 8);
            writer.AddOffset($"{prefix}dataNodeIndicesOffset", 8);

            // Nodes
            int dataIndex = -1;

            tree.DataNodeIndices = new List <int>();
            writer.FillInOffsetLong($"{prefix}nodesOffset", true, false);

            for (int i = 0; i < tree.Nodes.Count; ++i)
            {
                // Name
                var node = tree.Nodes[i];
                if (!string.IsNullOrEmpty(node.Name))
                {
                    writer.AddString($"{prefix}nodeNameOffset{i}", node.Name, 8);
                }
                else
                {
                    writer.Write(0UL);
                }

                // Data
                if (node.HasData)
                {
                    node.DataIndex = ++dataIndex;
                    writer.AddOffset($"{prefix}nodeDataOffset{dataIndex}", 8);
                    tree.DataNodeIndices.Add(i);
                }
                else
                {
                    writer.Write(0UL);
                }

                // Child Index Table Offset
                if (node.ChildCount > 0)
                {
                    writer.AddOffset($"{prefix}nodeChildIDTableOffset{i}", 8);
                }
                else
                {
                    writer.Write(0UL);
                }

                // Populate Child IDs
                if (node.ParentIndex >= 0)
                {
                    tree.Nodes[node.ParentIndex].ChildIDs.Add(i);
                }

                // Indices
                writer.Write(node.ParentIndex);
                writer.Write(i); // Global Index
                writer.Write(node.DataIndex);

                // Other
                writer.Write(node.ChildCount);
                writer.Write(node.HasData);
                writer.Write(node.FullPathSize);
            }
        }
Exemplo n.º 18
0
            public void Write(BINAWriter writer, NodeTree tree, string prefix)
            {
                // Name
                if (!string.IsNullOrEmpty(Name))
                {
                    writer.AddString($"{prefix}nodeNameOffset{Index}", Name, 8);
                }
                else
                {
                    writer.Write(0UL);
                }

                // Data
                bool hasData = (Data != null);

                if (hasData)
                {
                    writer.AddOffset($"{prefix}nodeDataOffset{Index}", 8);
                }
                else
                {
                    writer.Write(0UL);
                }

                // Child Index Table Offset
                if (ChildIndices.Count > 0)
                {
                    writer.AddOffset($"{prefix}nodeChildIDTableOffset{Index}", 8);
                }
                else
                {
                    writer.Write(0UL);
                }

                // Indices
                writer.Write(ParentIndex);
                writer.Write(Index);
                writer.Write(DataIndex);

                // Other
                writer.Write((ushort)ChildIndices.Count);
                writer.Write(hasData);

                // Full Path Size
                string pth;
                int    fullPathSize = 0;

                for (int i = ParentIndex; i > 0;)
                {
                    pth = tree.Nodes[i].Name;
                    i   = tree.Nodes[i].ParentIndex;

                    if (string.IsNullOrEmpty(pth))
                    {
                        continue;
                    }

                    fullPathSize += pth.Length;
                    if (fullPathSize > byte.MaxValue)
                    {
                        throw new NotSupportedException(
                                  "Forces cannot have file names > 255 characters in length!");
                    }
                }

                writer.Write((byte)fullPathSize);
            }
Exemplo n.º 19
0
        public int Save(Stream fileStream, uint?sizeLimit,
                        int startIndex = 0, List <string> splitList = null)
        {
            uint size      = 0;
            int  endIndex  = -1;
            bool isRootPAC = !sizeLimit.HasValue;

            // BINA Header
            var writer = new BINAWriter(fileStream, Header);

            if (Header.ID == 0)
            {
                // Get a random non-zero value between 1 and 0xFFFFFFFF
                // because I care too much™
                var rand = new Random();
                do
                {
                    Header.ID = unchecked ((uint)rand.Next(
                                               int.MinValue, int.MaxValue));
                }while (Header.ID == 0);
            }

            // Generate list of files to pack, categorized by extension
            var filesByExt = new Dictionary <string, List <DataContainer> >();

            for (int i = startIndex; i < Data.Count; ++i)
            {
                var file = (Data[i] as ArchiveFile);
                if (file == null)
                {
                    continue;
                }

                int extIndex = file.Name.IndexOf('.');
                if (extIndex == -1)
                {
                    Console.WriteLine(
                        "WARNING: Skipped {0} as it has no extension!",
                        file.Name);
                    continue;
                }

                string ext = file.Name.Substring(extIndex);
                if (!Types.ContainsKey(ext))
                {
                    Console.WriteLine(
                        "WARNING: Skipped {0} as its extension ({1}) is unsupported!",
                        file.Name, ext);
                    continue;
                }

                // Root-Exclusive Type Check
                var dataEntry = new DataEntry(file.Data);
                if (isRootPAC)
                {
                    dataEntry.DataType = (!RootExclusiveTypes.Contains(ext)) ?
                                         DataEntryTypes.NotHere : DataEntryTypes.Regular;;
                }
                else if (RootExclusiveTypes.Contains(ext))
                {
                    continue;
                }

                // BINA Header Check
                if (file.Data != null && file.Data.Length > 3 &&
                    file.Data[0] == 0x42 && file.Data[1] == 0x49 &&
                    file.Data[2] == 0x4E && file.Data[3] == 0x41)
                {
                    dataEntry.DataType = DataEntryTypes.BINAFile;
                }

                // Split if you exceed the sizeLimit
                if (!isRootPAC && sizeLimit.HasValue)
                {
                    // Not very accurate but close enough™
                    size += (uint)file.Data.Length;
                    if (size >= sizeLimit.Value)
                    {
                        endIndex = i;
                        break;
                    }
                }

                // Add Node to list, making the list first if necessary
                List <DataContainer> files;
                if (!filesByExt.ContainsKey(ext))
                {
                    files = new List <DataContainer>();
                    filesByExt.Add(ext, files);
                }
                else
                {
                    files = filesByExt[ext];
                }

                // We use substring instead of Path.GetFileNameWithoutExtension
                // to support files with multiple extensions (e.g. *.grass.bin)
                string shortName = file.Name.Substring(0, extIndex);
                files.Add(new DataContainer(shortName, dataEntry));
            }

            // Pack file list into Node Trees and generate types list
            //var fileTrees = new Dictionary<string, NodeTree>();
            var types = new List <DataContainer>();

            foreach (var fileType in filesByExt)
            {
                var fileTree = new NodeTree(fileType.Value)
                {
                    CustomData = fileType.Key.Substring(1)
                };

                types.Add(new DataContainer(
                              Types[fileType.Key], fileTree));
            }

            // Pack types list into Node Tree
            var typeTree = new NodeTree(types);

            // Write types Node Tree
            const string typeTreePrefix = "typeTree";

            typeTree.Write(writer, typeTreePrefix);

            // Write file Node Trees and generate an array of trees in the
            // same order as they'll be in the file for easier writing
            var fileTrees = new NodeTree[typeTree.DataNodeIndices.Count];

            for (int i = 0; i < fileTrees.Length; ++i)
            {
                int dataNodeIndex = typeTree.DataNodeIndices[i];
                var tree          = (NodeTree)typeTree.Nodes[dataNodeIndex].Data;

                writer.FillInOffsetLong(
                    $"{typeTreePrefix}nodeDataOffset{dataNodeIndex}",
                    true, false);

                fileTrees[i] = tree;
                tree.Write(writer, $"fileTree{i}");
            }

            // Write Data Node Indices
            typeTree.WriteDataIndices(writer, typeTreePrefix);
            for (int i = 0; i < fileTrees.Length; ++i)
            {
                fileTrees[i].WriteDataIndices(writer, $"fileTree{i}");
            }

            // Write Child Node Indices
            typeTree.WriteChildIndices(writer, typeTreePrefix);
            for (int i = 0; i < fileTrees.Length; ++i)
            {
                fileTrees[i].WriteChildIndices(writer, $"fileTree{i}");
            }

            // Write Split PACs section
            if (isRootPAC && splitList != null)
            {
                writer.Write((ulong)splitList.Count);
                writer.AddOffset($"splitPACsOffset", 8);
                writer.FillInOffsetLong($"splitPACsOffset", true, false);
                Header.SplitListLength += 16;

                for (int i = 0; i < splitList.Count; ++i)
                {
                    writer.AddString($"splitPACName{i}", splitList[i], 8);
                    Header.SplitListLength += 8;
                }
            }

            // Write File Entries
            long fileEntriesOffset = fileStream.Position;

            for (int i = 0; i < fileTrees.Length; ++i)
            {
                fileTrees[i].WriteDataEntries(writer, $"fileTree{i}",
                                              (string)fileTrees[i].CustomData, Header.ID);
            }

            // Write String Table
            uint stringTablePos = (uint)fileStream.Position;

            writer.WriteStringTable(Header);
            writer.FixPadding(8);

            // Write File Data
            long fileDataOffset = fileStream.Position;

            for (int i = 0; i < fileTrees.Length; ++i)
            {
                fileTrees[i].WriteData(writer, $"fileTree{i}",
                                       (string)fileTrees[i].CustomData);
            }

            // Write Offset Table
            writer.FixPadding(8);
            uint footerPos = writer.WriteFooter(Header);

            // Fill-In Header
            uint fileSize = (uint)fileStream.Position;

            writer.BaseStream.Position = 0;

            Header.NodeTreeLength = (uint)(fileEntriesOffset -
                                           PACxHeader.Length) - Header.SplitListLength;

            Header.FileEntriesLength = stringTablePos - (uint)fileEntriesOffset;
            Header.StringTableLength = (uint)fileDataOffset - stringTablePos;
            Header.DataLength        = (footerPos - (uint)fileDataOffset);

            // 5 if there are splits and this is the root, 2 if this is a split, 1 if no splits
            Header.PacType = (sizeLimit.HasValue) ? PACxHeader.PACTypes.IsSplit :
                             (splitList != null) ? PACxHeader.PACTypes.HasSplits :
                             PACxHeader.PACTypes.HasNoSplits;

            Header.SplitCount = (splitList == null) ? 0U : (uint)splitList.Count;
            Header.FinishWrite(writer);
            return(endIndex);
        }
Exemplo n.º 20
0
        public override void Save(Stream fileStream)
        {
            var  writer           = new BINAWriter(fileStream, Header);
            uint stringParamCount = 0;

            // Header
            writer.WriteNulls(0xC);
            if (Name != null)
            {
                writer.WriteNullTerminatedString(Name);
            }
            else
            {
                writer.WriteNullTerminatedString("test");
            }
            writer.WriteNulls(0x1B);
            writer.Write(Objects.Count);
            writer.AddOffset("objectTableOffset");
            writer.Write(Groups.Count);
            if (Groups.Count != 0)
            {
                writer.AddOffset("groupTableOffset");
            }
            else
            {
                writer.Write(0);
            }

            //Objects
            writer.FillInOffset("objectTableOffset", false);
            for (int i = 0; i < Objects.Count; i++)
            {
                //Object Values
                writer.AddString($"objectNameOffset{i}", $"{Objects[i].ObjectName}");
                writer.AddString($"objectTypeOffset{i}", $"{Objects[i].ObjectType}");
                writer.Write(Objects[i].UnknownBytes);
                writer.Write(Objects[i].Transform.Position);
                writer.Write(Objects[i].DrawDistance);
                writer.Write(Objects[i].Transform.Rotation);
                writer.Write(Objects[i].Parameters.Count);
                if (Objects[i].Parameters.Count != 0)
                {
                    writer.AddOffset($"parameterOffset{i}");
                }
                else
                {
                    writer.Write(0);
                }
            }

            for (int i = 0; i < Objects.Count; i++)
            {
                if (Objects[i].Parameters.Count != 0)
                {
                    writer.FillInOffset($"parameterOffset{i}", false);
                    foreach (var parameter in Objects[i].Parameters)
                    {
                        switch (parameter.DataType.ToString())
                        {
                        case "System.Boolean":
                            writer.Write(0);
                            writer.Write(((bool)parameter.Data) ? 1 : 0);
                            writer.Write(parameter.Unknown1);
                            writer.Write(parameter.Unknown2);
                            break;

                        case "System.Int32":
                            writer.Write(1);
                            writer.Write((int)parameter.Data);
                            writer.Write(parameter.Unknown1);
                            writer.Write(parameter.Unknown2);
                            break;

                        case "System.Single":
                            writer.Write(2);
                            writer.Write((float)parameter.Data);
                            writer.Write(parameter.Unknown1);
                            writer.Write(parameter.Unknown2);
                            break;

                        case "System.String":
                            writer.Write(3);
                            writer.AddString($"stringParamOffset{stringParamCount}", (string)parameter.Data);
                            writer.Write(parameter.Unknown1);
                            writer.Write(parameter.Unknown2);
                            stringParamCount++;
                            break;

                        case "HedgeLib.Vector3":
                            writer.Write(4);
                            writer.Write((Vector3)parameter.Data);
                            break;

                        case "System.UInt32":
                            writer.Write(6);
                            writer.Write((uint)parameter.Data);
                            writer.Write(parameter.Unknown1);
                            writer.Write(parameter.Unknown2);
                            break;

                        default:
                            Console.WriteLine(parameter.DataType.ToString());
                            writer.Write(0);
                            writer.Write(0);
                            writer.Write(0);
                            writer.Write(0);
                            break;
                        }
                        writer.Write(parameter.Unknown3);
                    }
                }

                /*
                 * //Object Parameters
                 * if (Objects[i].Parameters.Count != 0)
                 * {
                 *  Console.WriteLine($"Object {i}");
                 *  writer.FillInOffset($"parameterOffset{i}", false);
                 *  foreach (var parameter in Objects[i].Parameters)
                 *  {
                 *      if (parameter.DataType.ToString() == "System.Boolean")
                 *      {
                 *          Console.WriteLine("Boolean");
                 *          writer.Write(66);
                 *          writer.Write(((bool)parameter.Data) ? 1 : 0);
                 *          writer.Write(parameter.Unknown1);
                 *          writer.Write(parameter.Unknown2);
                 *          writer.Write(parameter.Unknown3);
                 *      }
                 *      else if (parameter.DataType.ToString() == "System.Int32")
                 *      {
                 *          Console.WriteLine("Int32");
                 *          writer.Write(77);
                 *          writer.Write((int)parameter.Data);
                 *          writer.Write(parameter.Unknown1);
                 *          writer.Write(parameter.Unknown2);
                 *          writer.Write(parameter.Unknown3);
                 *      }
                 *      else if (parameter.DataType.ToString() == "System.Single")
                 *      {
                 *          Console.WriteLine("Single");
                 *          writer.Write(88);
                 *          writer.Write((float)parameter.Data);
                 *          writer.Write(parameter.Unknown1);
                 *          writer.Write(parameter.Unknown2);
                 *          writer.Write(parameter.Unknown3);
                 *      }
                 *      else if (parameter.DataType.ToString() == "System.String")
                 *      {
                 *          Console.WriteLine("String");
                 *          writer.Write(99);
                 *          writer.AddString($"offset{stringParamCount}", (string)parameter.Data);
                 *          writer.Write(parameter.Unknown1);
                 *          writer.Write(parameter.Unknown2);
                 *          writer.Write(parameter.Unknown3);
                 *
                 ++stringParamCount;
                 *      }
                 *      else if (parameter.DataType.ToString() == "HedgeLib.Vector3")
                 *      {
                 *          Console.WriteLine("Vector3");
                 *          writer.Write(55);
                 *          writer.Write((Vector3)parameter.Data);
                 *          writer.Write(parameter.Unknown3);
                 *      }
                 *      else if (parameter.DataType.ToString() == "System.UInt32")
                 *      {
                 *          Console.WriteLine("UInt32");
                 *          writer.Write(44);
                 *          writer.Write((uint)parameter.Data);
                 *          writer.Write(parameter.Unknown1);
                 *          writer.Write(parameter.Unknown2);
                 *          writer.Write(parameter.Unknown3);
                 *      }
                 *      else
                 *      {
                 *          Console.WriteLine("Unhandled Data Type!");
                 *          writer.Write(0L);
                 *      }
                 *      writer.FixPadding(0x14);
                 *  }
                 * }*/
            }

            //Groups
            if (Groups.Count != 0)
            {
                writer.FillInOffset("groupTableOffset", false);
                for (int i = 0; i < Groups.Count; i++)
                {
                    writer.AddString($"groupNameOffset{i}", $"{Groups[i].GroupName}");
                    writer.AddString($"groupTypeOffset{i}", $"{Groups[i].GroupType}");
                    writer.Write(Groups[i].GroupObjectCount);
                    writer.AddOffset($"groupObjectList{i}");
                }


                for (int i = 0; i < Groups.Count; i++)
                {
                    writer.FillInOffset($"groupObjectList{i}", false);
                    for (int c = 0; c < Groups[i].ObjectIDs.Count; c++)
                    {
                        writer.Write(0);
                        writer.Write(Groups[i].ObjectIDs[c]);
                    }
                }
            }
            //writer.WriteNulls(572);
            // Write Footer
            writer.FinishWrite(Header);
        }
        public int Save(Stream fileStream, uint?sizeLimit,
                        int startIndex = 0, List <string> splitList = null)
        {
            uint size      = 0;
            int  endIndex  = -1;
            bool isRootPAC = (!sizeLimit.HasValue && splitList != null);

            // BINA Header
            var writer = new BINAWriter(fileStream, Header);

            if (Header.ID == 0)
            {
                // Get a random non-zero value between 1 and 0xFFFFFFFF
                // because I care too much™
                var rand = new Random();
                do
                {
                    Header.ID = unchecked ((uint)rand.Next(
                                               int.MinValue, int.MaxValue));
                }while (Header.ID == 0);
            }

            // Generate Node Trees
            var typeTree = new NodeTree();

            typeTree.Nodes.Add(new Node()
            {
                ChildCount = 1,
            });

            typeTree.Nodes.Add(new Node()
            {
                Name        = "Res",
                ParentIndex = 0,
            });

            var fileTrees = new Dictionary <string, NodeTree>();

            for (int i = startIndex; i < Data.Count; ++i)
            {
                var file = (Data[i] as ArchiveFile);
                if (file == null)
                {
                    continue;
                }

                string ext       = file.Name.Substring(file.Name.IndexOf('.'));
                string shortName = file.Name.Substring(0,
                                                       file.Name.Length - ext.Length);

                if (!Types.ContainsKey(ext))
                {
                    Console.WriteLine(
                        "WARNING: Skipped {0} as its extension ({1}) is unsupported!",
                        file.Name, ext);
                    continue;
                }

                // Root-Exclusive Type Check
                ulong fileDataType = 0;
                if (isRootPAC)
                {
                    fileDataType = (RootExclusiveTypes.Contains(ext)) ?
                                   0UL : 1UL;
                }

                // BINA Header Check
                if (file.Data[0] == 0x42 && file.Data[1] == 0x49 &&
                    file.Data[2] == 0x4E && file.Data[3] == 0x41)
                {
                    fileDataType = 2;
                }

                if (!isRootPAC && RootExclusiveTypes.Contains(ext))
                {
                    continue;
                }

                NodeTree fileTree;
                string   pacType = Types[ext];

                // TODO: Do node name splitting more like the game does it
                if (!fileTrees.ContainsKey(ext))
                {
                    ++typeTree.Nodes[1].ChildCount;
                    ++typeTree.DataNodeCount;
                    typeTree.Nodes.Add(new Node()
                    {
                        FullPathSize = 3,
                        Name         = pacType.Substring(3),
                        ParentIndex  = 1,
                        ChildCount   = 1
                    });

                    typeTree.Nodes.Add(new Node()
                    {
                        FullPathSize = (byte)pacType.Length,
                        ParentIndex  = typeTree.Nodes.Count - 1,
                        DataOffset   = -1,
                        HasData      = true
                    });

                    fileTree = new NodeTree();
                    fileTree.Nodes.Add(new Node());

                    fileTrees.Add(ext, fileTree);
                }
                else
                {
                    fileTree = fileTrees[ext];
                }

                ++fileTree.Nodes[0].ChildCount;
                ++fileTree.DataNodeCount;
                fileTree.Nodes.Add(new Node()
                {
                    Name        = shortName,
                    ParentIndex = 0,
                    ChildCount  = 1
                });

                fileTree.Nodes.Add(new Node()
                {
                    ArchiveFileIndex = i,
                    DataOffset       = -1,
                    ParentIndex      = fileTree.Nodes.Count - 1,
                    FullPathSize     = (byte)shortName.Length,
                    HasData          = true,
                    DataType         = fileDataType
                });

                // Split if you exceed the sizeLimit
                if (sizeLimit.HasValue && i < Data.Count - 1)
                {
                    // Not very accurate but close enough™
                    size += (uint)(0x40 + file.Data.Length);

                    if (size >= sizeLimit.Value)
                    {
                        endIndex = i + 1;
                        break;
                    }
                }
            }

            // Write Node Trees
            WriteNodeTree(writer, typeTree, "typeTree");

            int nodeTreeIndex = -1;

            foreach (var fileTree in fileTrees)
            {
                writer.FillInOffsetLong(
                    $"typeTreenodeDataOffset{++nodeTreeIndex}", true, false);

                WriteNodeTree(writer, fileTree.Value, Types[fileTree.Key]);
            }

            // Write Data Node Indices
            WriteTreeDataIndices(writer, typeTree, "typeTree");
            foreach (var fileTree in fileTrees)
            {
                WriteTreeDataIndices(writer, fileTree.Value, Types[fileTree.Key]);
            }

            // Write Child Node Indices
            for (int i = 0; i < typeTree.Nodes.Count; ++i)
            {
                var node = typeTree.Nodes[i];
                if (node.ChildCount < 1)
                {
                    continue;
                }

                writer.FillInOffsetLong(
                    $"typeTreenodeChildIDTableOffset{i}", true, false);

                for (int i2 = 0; i2 < node.ChildCount; ++i2)
                {
                    writer.Write(node.ChildIDs[i2]);
                }

                writer.FixPadding(8);
            }

            foreach (var fileTree in fileTrees)
            {
                var tree = fileTree.Value;
                for (int i = 0; i < tree.Nodes.Count; ++i)
                {
                    var node = tree.Nodes[i];
                    if (node.ChildCount < 1)
                    {
                        continue;
                    }

                    writer.FillInOffsetLong(
                        $"{Types[fileTree.Key]}nodeChildIDTableOffset{i}", true, false);

                    for (int i2 = 0; i2 < node.ChildCount; ++i2)
                    {
                        writer.Write(node.ChildIDs[i2]);
                    }

                    writer.FixPadding(8);
                }
            }

            // Write PACs section
            Header.SplitListLength = 0;
            if (isRootPAC)
            {
                writer.Write((ulong)splitList.Count);
                writer.AddOffset("splitPACsOffset", 8);
                Header.SplitListLength += 16;

                writer.FillInOffsetLong("splitPACsOffset", true, false);
                for (int i = 0; i < splitList.Count; ++i)
                {
                    writer.AddString($"splitPACName{i}", splitList[i], 8);
                    Header.SplitListLength += 8;
                }
            }

            // Write File Entries
            long fileEntriesOffset = fileStream.Position;

            foreach (var fileTree in fileTrees)
            {
                var tree = fileTree.Value;
                for (int i = 0; i < tree.DataNodeCount; ++i)
                {
                    var node = tree.Nodes[tree.DataNodeIndices[i]];
                    writer.FillInOffsetLong(
                        $"{Types[fileTree.Key]}nodeDataOffset{i}", true, false);

                    var file = Data[node.ArchiveFileIndex] as ArchiveFile;
                    writer.Write(Header.ID);
                    writer.Write((ulong)file.Data.Length);
                    writer.Write(0U);

                    if (node.DataType == 1)
                    {
                        writer.Write(0UL);
                    }
                    else
                    {
                        writer.AddOffset($"{Types[fileTree.Key]}fileDataOffset{i}", 8);
                    }

                    writer.Write(0UL);
                    writer.AddString($"{Types[fileTree.Key]}extDataOffset{i}",
                                     fileTree.Key.Substring(1), 8);
                    writer.Write(node.DataType);
                }
            }

            // Write String Table
            uint stringTablePos = writer.WriteStringTable();

            writer.FixPadding(8);

            // Write File Data
            long fileDataOffset = fileStream.Position;

            foreach (var fileTree in fileTrees)
            {
                var tree = fileTree.Value;
                for (int i = 0; i < tree.DataNodeCount; ++i)
                {
                    var node = tree.Nodes[tree.DataNodeIndices[i]];
                    if (node.DataType == 1)
                    {
                        continue;
                    }

                    writer.FixPadding(16);
                    writer.FillInOffsetLong(
                        $"{Types[fileTree.Key]}fileDataOffset{i}", true, false);

                    var file = Data[node.ArchiveFileIndex] as ArchiveFile;
                    writer.Write(file.Data);
                }
            }

            // Write Offset Table
            writer.FixPadding(8);
            uint footerPos = writer.WriteFooter(Header);

            // Fill-In Header
            uint fileSize = (uint)fileStream.Position;

            writer.BaseStream.Position = 0;

            Header.NodeTreeLength = (uint)(fileEntriesOffset -
                                           PACxHeader.Length) - Header.SplitListLength;

            Header.FileEntriesLength = stringTablePos - (uint)fileEntriesOffset;
            Header.StringTableLength = (uint)fileDataOffset - stringTablePos;
            Header.DataLength        = (footerPos - (uint)fileDataOffset);

            // 5 if there are splits and this is the root, 2 if this is a split, 1 if no splits
            Header.PacType = (sizeLimit.HasValue) ? PACxHeader.PACTypes.IsSplit :
                             (splitList != null) ? PACxHeader.PACTypes.HasSplits :
                             PACxHeader.PACTypes.HasNoSplits;

            Header.SplitCount = (splitList == null) ? 0U : (uint)splitList.Count;
            Header.FinishWrite(writer);
            return(endIndex);
        }
Exemplo n.º 22
0
        private static void WriteObject(BINAWriter writer, SetObject obj, SOBJType type,
                                        bool rawDataMode = false) // true = full, false = only remaining bytes)
        {
            // Get a bunch of values from the object's custom data, if present.
            uint  unknown1 = obj.GetCustomDataValue <ushort>("Unknown1");
            uint  unknown2 = obj.GetCustomDataValue <uint>("Unknown2");
            uint  unknown3 = obj.GetCustomDataValue <uint>("Unknown3");
            float unknown4 = obj.GetCustomDataValue <float>("Unknown4");

            float rangeIn  = obj.GetCustomDataValue <float>("RangeIn");
            float rangeOut = obj.GetCustomDataValue <float>("RangeOut");
            uint  parent   = (type == SOBJType.LostWorld) ?
                             obj.GetCustomDataValue <uint>("Parent") : 0;

            var rawParamData = obj.GetCustomDataValue <byte[]>("RawParamData");

            // Combine the two values back into one so we can write with correct endianness.
            uint unknownData = (unknown1 << 16) | (obj.ObjectID & 0xFFFF);

            writer.Write(unknownData);

            writer.Write(unknown2);
            writer.Write(unknown3);
            writer.Write(unknown4);

            writer.Write(rangeIn);
            writer.Write(rangeOut);
            if (type == SOBJType.LostWorld)
            {
                writer.Write(parent);
            }
            writer.FixPadding(4);
            writer.AddOffset($"transformsOffset_{obj.ObjectID}");

            writer.Write((uint)obj.Children.Length + 1);
            writer.WriteNulls((type == SOBJType.LostWorld) ? 0xC : 4u);

            // Parameters
            long paramBegin = writer.BaseStream.Position;

            foreach (var param in obj.Parameters)
            {
                // Write Special Types/Fix Padding
                if (param.DataType == typeof(uint[]))
                {
                    // Data Info
                    var arr = (uint[])param.Data;
                    writer.FixPadding(4);

                    writer.AddOffset("arrOffset");
                    writer.Write((uint)arr.Length);
                    writer.WriteNulls(4); // TODO: Figure out what this is.

                    // Data
                    writer.FillInOffset("arrOffset", false);

                    foreach (uint value in arr)
                    {
                        writer.Write(value);
                    }

                    continue;
                }
                else if (param.DataType == typeof(string))
                {
                    // Data Info
                    string str = (string)param.Data;
                    writer.AddOffset("strOffset");
                    writer.WriteNulls(4); // TODO: Figure out what this is.

                    if (string.IsNullOrEmpty(str))
                    {
                        writer.FillInOffset("strOffset", 0, true);
                    }
                    else
                    {
                        writer.FillInOffset("strOffset", false);
                        writer.WriteNullTerminatedString(str);
                    }

                    continue;
                }
                else if (param.DataType == typeof(float) ||
                         param.DataType == typeof(int) || param.DataType == typeof(uint))
                {
                    writer.FixPadding(4);
                }
                else if (type == SOBJType.LostWorld && param.DataType == typeof(Vector3))
                {
                    writer.FixPadding(16);
                }

                // Write Data
                writer.WriteByType(param.DataType, param.Data);
            }

            // Write remaining raw data from loaded ORC
            if (rawDataMode == false)
            {
                writer.Write(rawParamData);
            }
            else
            {
                int knownParamLength = (int)(writer.BaseStream.Position - paramBegin);
                writer.Write(rawParamData, knownParamLength,
                             rawParamData.Length - knownParamLength);
            }

            writer.FixPadding(4);
        }
Exemplo n.º 23
0
        public static void Write(BINAWriter writer, List <SetObject> objects, SOBJType type)
        {
            // Get some data we need to write the file
            var  objectsByType = new Dictionary <string, List <int> >();
            uint transformCount = 0, objTypeCount = 0;

            for (int objIndex = 0; objIndex < objects.Count; ++objIndex)
            {
                var obj = objects[objIndex];
                if (!objectsByType.ContainsKey(obj.ObjectType))
                {
                    objectsByType.Add(obj.ObjectType, new List <int>()
                    {
                        objIndex
                    });
                    ++objTypeCount;
                }
                else
                {
                    objectsByType[obj.ObjectType].Add(objIndex);
                }

                transformCount += (uint)obj.Children.Length + 1;
            }

            // SOBJ Header
            var sig = Signature.ToCharArray();

            if (!writer.IsBigEndian)
            {
                Array.Reverse(sig);
            }

            writer.Write(sig);
            writer.Write(1u); // TODO: Figure out what this value is.
            writer.Write(objTypeCount);
            writer.AddOffset("objTypeOffsetsOffset");

            writer.Write((type == SOBJType.LostWorld) ?
                         0 : 0xFFFFFFFF); // I doubt this matters at all tbh.
            writer.AddOffset("objOffsetsOffset");
            writer.Write(objects.Count);
            writer.WriteNulls(4);

            writer.Write(transformCount);

            // Object Offsets
            writer.FillInOffset("objOffsetsOffset", false);
            writer.AddOffsetTable("objOffset", (uint)objects.Count);

            // Object Types
            uint i = 0;

            writer.FillInOffset("objTypeOffsetsOffset", false);

            foreach (var obj in objectsByType)
            {
                writer.AddString($"objName_{i}", obj.Key);
                writer.Write((uint)obj.Value.Count);
                writer.AddOffset($"objIndicesOffset_{i}");

                ++i;
            }

            // Object Indices
            ushort i2 = 0;

            i = 0;

            foreach (var obj in objectsByType)
            {
                writer.FillInOffset($"objIndicesOffset_{i}", false);
                for (int i3 = 0; i3 < obj.Value.Count; ++i3)
                {
                    writer.Write(i2);
                    ++i2;
                }

                ++i;
            }

            // Objects
            writer.FixPadding(4);
            i = 0;

            foreach (var objType in objectsByType)
            {
                foreach (int objIndex in objType.Value)
                {
                    writer.FillInOffset($"objOffset_{i}", false);
                    WriteObject(writer, objects[objIndex], type);
                    writer.FixPadding(0x4);
                    ++i;
                }
            }

            // TODO: Clean this up
            writer.FixPadding(4);

            foreach (var objType in objectsByType)
            {
                foreach (int objIndex in objType.Value)
                {
                    // Transforms
                    writer.FixPadding(0x4);
                    writer.FillInOffset($"transformsOffset_{objects[objIndex].ObjectID}", false);
                    WriteTransform(writer, objects[objIndex].Transform,
                                   type == SOBJType.LostWorld);

                    foreach (var childTransform in objects[objIndex].Children)
                    {
                        WriteTransform(writer, childTransform,
                                       type == SOBJType.LostWorld);
                    }
                }
            }
        }
Exemplo n.º 24
0
        public override void Save(Stream fileStream)
        {
            //Determine amount of Cues that use a CSB and amount that use an XMA
            int csbCueCount    = 0;
            int streamCueCount = 0;

            for (int i = 0; i < Cues.Count; i++)
            {
                if (Cues[i].Stream == null)
                {
                    csbCueCount++;
                }
                else
                {
                    streamCueCount++;
                }
            }

            // Header
            var writer = new BINAWriter(fileStream, Header);

            writer.WriteSignature(Signature);
            writer.Write(537265920); //Hardcoded as all Scene Banks seem to have this number in this position.
            writer.AddOffset("banksOffset");
            writer.AddOffset("cueNamesOffset");
            writer.AddOffset("cueIndiciesOffset");
            writer.AddOffset("streamsOffset");
            writer.FillInOffset("banksOffset", false);
            writer.Write(Name);
            writer.Write(Cues.Count);
            writer.Write(csbCueCount);
            writer.Write(streamCueCount);

            //Cue Information
            writer.FillInOffset("cueNamesOffset", false);
            int csbCueID    = 0;
            int streamCueID = 0;

            for (int i = 0; i < Cues.Count; i++)
            {
                writer.Write(Cues[i].Name);
                if (Cues[i].Stream == null)
                {
                    writer.Write(0);
                    writer.Write(csbCueID);
                    csbCueID++;
                }
                else
                {
                    writer.Write(1);
                    writer.Write(streamCueID);
                    streamCueID++;
                }
                writer.Write(Cues[i].Category);
                writer.Write(Cues[i].Unknown1);
                writer.Write(Cues[i].Unknown2);
            }

            //CSB Cue ID List
            writer.FillInOffset("cueIndiciesOffset", false);
            for (int i = 0; i < csbCueCount; i++)
            {
                writer.Write(i);
            }

            //Stream Names
            if (streamCueCount != 0)
            {
                writer.FillInOffset("streamsOffset", false);
                for (int i = 0; i < Cues.Count; i++)
                {
                    if (Cues[i].Stream != null)
                    {
                        writer.AddString($"streamOffset{i}", $"{Cues[i].Stream}");
                    }
                }
            }

            writer.FinishWrite(Header);
        }