Beispiel #1
0
            internal void Write(BinaryWriterEx bw)
            {
                long start = bw.Position;

                bw.ReserveInt64("NameOffset");
                bw.WriteUInt32((uint)Type);
                bw.WriteInt32(ID);
                bw.WriteInt32(modelIndex);
                bw.WriteInt32(0);
                bw.ReserveInt64("PlaceholderOffset");
                bw.WriteVector3(Position);
                bw.WriteVector3(Rotation);
                bw.WriteVector3(Scale);

                bw.WriteUInt32(DrawGroup1);
                bw.WriteUInt32(DrawGroup2);
                bw.WriteUInt32(DrawGroup3);
                bw.WriteUInt32(DrawGroup4);
                bw.WriteUInt32(DispGroup1);
                bw.WriteUInt32(DispGroup2);
                bw.WriteUInt32(DispGroup3);
                bw.WriteUInt32(DispGroup4);

                bw.WriteInt32(UnkF01);
                bw.WriteInt32(UnkF02);
                bw.WriteInt32(UnkF03);
                bw.WriteInt32(UnkF04);
                bw.WriteInt32(UnkF05);
                bw.WriteInt32(UnkF06);
                bw.WriteInt32(UnkF07);
                bw.WriteInt32(UnkF08);
                bw.WriteInt32(UnkF09);
                bw.WriteInt32(UnkF10);
                bw.WriteInt32(UnkF11);
                bw.WriteInt32(UnkF12);
                bw.WriteInt32(UnkF13);
                bw.WriteInt32(UnkF14);
                bw.WriteInt32(UnkF15);
                bw.WriteInt32(UnkF16);
                bw.WriteInt32(UnkF17);
                bw.WriteInt32(UnkF18);
                bw.WriteInt32(0);

                bw.ReserveInt64("BaseDataOffset");
                bw.ReserveInt64("TypeDataOffset");
                bw.ReserveInt64("UnkOffset1");
                bw.ReserveInt64("UnkOffset2");

                bw.FillInt64("NameOffset", bw.Position - start);
                bw.WriteUTF16(Name, true);
                if (Placeholder == null)
                {
                    bw.FillInt64("PlaceholderOffset", 0);
                }
                else
                {
                    bw.FillInt64("PlaceholderOffset", bw.Position - start);
                    bw.WriteUTF16(Placeholder, true);
                }
                bw.Pad(8);

                bw.FillInt64("BaseDataOffset", bw.Position - start);
                bw.WriteInt32(EventEntityID);

                bw.WriteSByte(LightID);
                bw.WriteSByte(FogID);
                bw.WriteSByte(ScatterID);
                bw.WriteSByte(LensFlareID);

                bw.WriteInt32(0);

                bw.WriteSByte(LanternID);
                bw.WriteSByte(LodParamID);
                bw.WriteSByte(UnkB0E);
                bw.WriteBoolean(IsShadowDest);

                bw.WriteBoolean(IsShadowOnly);
                bw.WriteBoolean(DrawByReflectCam);
                bw.WriteBoolean(DrawOnlyReflectCam);
                bw.WriteBoolean(UseDepthBiasFloat);

                bw.WriteBoolean(DisablePointLightEffect);
                bw.WriteByte(UnkB15);
                bw.WriteByte(UnkB16);
                bw.WriteByte(UnkB17);

                bw.WriteInt32(UnkB18);
                bw.WriteInt32(UnkB1C);
                bw.WriteInt32(UnkB20);
                bw.WriteInt32(UnkB24);
                bw.WriteInt32(UnkB28);
                bw.WriteInt32(-1);
                bw.WriteInt32(UnkB30);
                bw.WriteInt32(UnkB34);
                bw.WriteInt32(UnkB38);
                bw.WriteInt32(0);

                bw.FillInt64("TypeDataOffset", bw.Position - start);
                if (UnkOffset1Delta == 0)
                {
                    bw.FillInt64("UnkOffset1", 0);
                }
                else
                {
                    bw.FillInt64("UnkOffset1", bw.Position - start + UnkOffset1Delta);
                }

                if (UnkOffset2Delta == 0)
                {
                    bw.FillInt64("UnkOffset2", 0);
                }
                else
                {
                    bw.FillInt64("UnkOffset2", bw.Position - start + UnkOffset2Delta);
                }

                WriteSpecific(bw);
            }
Beispiel #2
0
 internal void WriteHeader(BinaryWriterEx bw, int i)
 {
     bw.WriteInt64(ID);
     bw.ReserveInt64($"AnimationOffset{i}");
 }
Beispiel #3
0
        internal override void Write(BinaryWriterEx bw)
        {
            if (layout == null)
            {
                throw new InvalidOperationException("Params cannot be written without a layout.");
            }

            Rows.Sort((r1, r2) => r1.ID.CompareTo(r2.ID));

            bw.BigEndian = BigEndian;
            void WriteFormat()
            {
                bw.WriteByte((byte)(BigEndian ? 0xFF : 0x00));
                bw.WriteByte(Format2D);
                bw.WriteByte(Format2E);
                bw.WriteByte(Format2F);
            }

            // DeS, DS1
            if ((Format2D & 0x7F) < 3)
            {
                bw.ReserveUInt32("StringsOffset");
                bw.ReserveUInt16("DataStart");
                bw.WriteInt16(Unk06);
                bw.WriteInt16(Unk08);
                bw.WriteUInt16((ushort)Rows.Count);
                bw.WriteFixStr(ID, 0x20, 0x20);
                WriteFormat();
            }
            // DS2
            else if ((Format2D & 0x7F) == 3)
            {
                bw.ReserveUInt32("StringsOffset");
                bw.WriteInt16(0);
                bw.WriteInt16(Unk06);
                bw.WriteInt16(Unk08);
                bw.WriteUInt16((ushort)Rows.Count);
                bw.WriteFixStr(ID, 0x20, 0x20);
                WriteFormat();
                bw.ReserveUInt32("DataStart");
                bw.WriteInt32(0);
                bw.WriteInt32(0);
                bw.WriteInt32(0);
            }
            // SotFS, BB
            else if ((Format2D & 0x7F) == 4)
            {
                bw.ReserveUInt32("StringsOffset");
                bw.WriteInt16(0);
                bw.WriteInt16(Unk06);
                bw.WriteInt16(Unk08);
                bw.WriteUInt16((ushort)Rows.Count);
                bw.WriteFixStr(ID, 0x20, 0x00);
                WriteFormat();
                bw.ReserveInt64("DataStart");
                bw.WriteInt64(0);
            }
            // DS3, SDT
            else
            {
                bw.ReserveUInt32("StringsOffset");
                bw.WriteInt16(0);
                bw.WriteInt16(Unk06);
                bw.WriteInt16(Unk08);
                bw.WriteUInt16((ushort)Rows.Count);
                bw.WriteInt32(0);
                bw.ReserveInt64("IDOffset");
                bw.WritePattern(0x14, 0x00);
                WriteFormat();
                bw.ReserveInt64("DataStart");
                bw.WriteInt64(0);
            }

            for (int i = 0; i < Rows.Count; i++)
            {
                Rows[i].WriteHeader(bw, Format2D, i);
            }

            if ((Format2D & 0x7F) < 3)
            {
                bw.FillUInt16("DataStart", (ushort)bw.Position);
            }
            else if ((Format2D & 0x7F) == 3)
            {
                bw.FillUInt32("DataStart", (uint)bw.Position);
            }
            else
            {
                bw.FillInt64("DataStart", bw.Position);
            }

            for (int i = 0; i < Rows.Count; i++)
            {
                Rows[i].WriteCells(bw, Format2D, i, layout);
            }

            bw.FillUInt32("StringsOffset", (uint)bw.Position);

            if ((Format2D & 0x7F) > 4)
            {
                bw.FillInt64("IDOffset", bw.Position);
                bw.WriteASCII(ID, true);
            }

            for (int i = 0; i < Rows.Count; i++)
            {
                Rows[i].WriteName(bw, Format2D, i);
            }
        }
Beispiel #4
0
        internal override void Write(BinaryWriterEx bw)
        {
            bw.WriteASCII("EVD\0");

            if (Game == GameType.DS1)
            {
                bw.WriteUInt32(0);
                bw.WriteUInt32(0xCC);
            }
            else if (Game == GameType.BB)
            {
                bw.WriteUInt32(0xFF00);
                bw.WriteUInt32(0xCC);
            }
            else if (Game == GameType.DS3)
            {
                bw.WriteUInt32(0x1FF00);
                bw.WriteUInt32(0xCD);
            }

            void ReserveIntW(string name, bool?isWide = null)
            {
                if (isWide ?? Game != GameType.DS1)
                {
                    bw.ReserveInt64(name);
                }
                else
                {
                    bw.ReserveInt32(name);
                }
            }

            void FillIntW(string name, long value, bool?isWide = null)
            {
                if (isWide ?? Game != GameType.DS1)
                {
                    bw.FillInt64(name, value);
                }
                else
                {
                    bw.FillInt32(name, (int)value);
                }
            }

            void WriteIntW(long value, bool?isWide = null)
            {
                if (isWide ?? Game != GameType.DS1)
                {
                    bw.WriteInt64(value);
                }
                else
                {
                    bw.WriteInt32((int)value);
                }
            }

            if (Game == GameType.BB)
            {
                bw.ReserveInt64("FileLength");
            }
            else
            {
                bw.ReserveInt32("FileLength");
            }

            WriteIntW(Events.Count);
            ReserveIntW("EventsOffset");
            ReserveIntW("InstructionsCount");
            ReserveIntW("InstructionsOffset");

            //Dummy count. Always empty.
            WriteIntW(0);
            // Same as EventLayersOffset because it's always empty.
            ReserveIntW("DummiesOffset");
            ReserveIntW("EventLayersCount");
            ReserveIntW("EventLayersOffset");
            ReserveIntW("ParametersCount");
            ReserveIntW("ParametersOffset");
            WriteIntW(LinkedFileStringIndices.Count);
            ReserveIntW("LinkedFilesOffset");
            ReserveIntW("ArgsBlockSize");
            ReserveIntW("ArgsBlockOffset");
            ReserveIntW("StringsBlockSize");
            ReserveIntW("StringsBlockOffset");

            if (Game == GameType.DS1)
            {
                bw.WriteInt32(0);
            }

            // Events
            FillIntW("EventsOffset", bw.Position);
            for (int i = 0; i < Events.Count; i++)
            {
                Events[i].Write(bw, Game, i);
            }

            // Instructions
            long instructionsOffset = bw.Position;

            FillIntW("InstructionsOffset", instructionsOffset);
            long instructionsCount = 0;

            for (int i = 0; i < Events.Count; i++)
            {
                FillIntW($"EventInstructionsOffset{i}", bw.Position - instructionsOffset);
                for (int j = 0; j < Events[i].Instructions.Count; j++)
                {
                    Events[i].Instructions[j].Write(bw, Game, i, j);
                }
                instructionsCount += Events[i].Instructions.Count;
            }
            FillIntW("InstructionsCount", instructionsCount);

            // Dummies
            FillIntW("DummiesOffset", bw.Position);

            // EventLayers
            long eventLayersOffset = bw.Position;

            FillIntW("EventLayersOffset", eventLayersOffset);
            long eventLayersCount = 0;

            for (int i = 0; i < Events.Count; i++)
            {
                for (int j = 0; j < Events[i].Instructions.Count; j++)
                {
                    if (Events[i].Instructions[j].Layer != null)
                    {
                        if (Game == GameType.DS3)
                        {
                            bw.FillInt64($"InstructionLayerOffset{i}:{j}", bw.Position - eventLayersOffset);
                        }
                        else
                        {
                            bw.FillInt32($"InstructionLayerOffset{i}:{j}", (int)(bw.Position - eventLayersOffset));
                        }
                        Events[i].Instructions[j].Layer.Write(bw, Game);
                        eventLayersCount++;
                    }
                }
            }
            FillIntW("EventLayersCount", eventLayersCount);

            // Args
            long argsBlockOffset = bw.Position;

            FillIntW("ArgsBlockOffset", argsBlockOffset);
            for (int i = 0; i < Events.Count; i++)
            {
                for (int j = 0; j < Events[i].Instructions.Count; j++)
                {
                    if (Events[i].Instructions[j].Args.Length > 0)
                    {
                        bw.FillInt32($"InstructionArgsOffset{i}:{j}", (int)(bw.Position - argsBlockOffset));
                        bw.WriteBytes(Events[i].Instructions[j].Args);
                        //bw.Pad(4);
                    }
                }
            }

            if (Game == GameType.DS1)
            {
                if ((bw.Position - argsBlockOffset) % 16 > 0)
                {
                    bw.WritePattern(16 - (int)(bw.Position - argsBlockOffset) % 16, 0x00);
                }
            }
            else
            {
                bw.Pad(16);
            }

            FillIntW("ArgsBlockSize", bw.Position - argsBlockOffset);

            // Parameters
            long parametersOffset = bw.Position;

            FillIntW("ParametersOffset", parametersOffset);
            long parametersCount = 0;

            for (int i = 0; i < Events.Count; i++)
            {
                if (Events[i].Parameters.Count > 0)
                {
                    if (Game == GameType.DS3)
                    {
                        bw.FillInt64($"EventParametersOffset{i}", bw.Position - parametersOffset);
                    }
                    else
                    {
                        bw.FillInt32($"EventParametersOffset{i}", (int)(bw.Position - parametersOffset));
                    }
                    for (int j = 0; j < Events[i].Parameters.Count; j++)
                    {
                        Events[i].Parameters[j].Write(bw, Game);
                    }
                    parametersCount += Events[i].Parameters.Count;
                }
            }
            FillIntW("ParametersCount", parametersCount);

            // Linked Files
            FillIntW("LinkedFilesOffset", bw.Position);
            for (int i = 0; i < LinkedFileStringIndices.Count; i++)
            {
                ReserveIntW($"LinkedFileStringOffset{i}");
            }

            // Strings
            FillIntW("StringsBlockOffset", bw.Position);
            long        stringsStartOffset = bw.Position;
            List <long> stringTableOffsets = new List <long>();

            for (int i = 0; i < StringTable.Count; i++)
            {
                stringTableOffsets.Add(bw.Position - stringsStartOffset);
                bw.WriteUTF16(StringTable[i], terminate: true);
            }
            FillIntW("StringsBlockSize", bw.Position - stringsStartOffset);

            // Linked Files - Second Pass
            for (int i = 0; i < LinkedFileStringIndices.Count; i++)
            {
                FillIntW($"LinkedFileStringOffset{i}", stringTableOffsets[LinkedFileStringIndices[i]]);
            }

            if (Game == GameType.BB)
            {
                bw.FillInt64("FileLength", bw.Position);
            }
            else
            {
                bw.FillInt32("FileLength", (int)bw.Position);
            }
        }
Beispiel #5
0
        internal override void Write(BinaryWriterEx bw)
        {
            bw.WriteASCII("TAE ");
            bw.WriteByte(0);
            bw.WriteByte(0);
            bw.WriteByte(0);
            bw.WriteByte(0xFF);
            bw.WriteInt32(0x1000C);
            bw.ReserveInt32("FileSize");
            bw.WriteInt64(0x40);
            bw.WriteInt64(1);
            bw.WriteInt64(0x50);
            bw.WriteInt64(0x80);
            bw.WriteInt64(Unk30);
            bw.WriteInt64(0);
            bw.WriteBytes(Flags);
            bw.WriteInt64(1);
            bw.WriteInt32(ID);
            bw.WriteInt32(Animations.Count);
            bw.ReserveInt64("AnimsOffset");
            bw.ReserveInt64("AnimGroupsOffset");
            bw.WriteInt64(0xA0);
            bw.WriteInt64(Animations.Count);
            bw.ReserveInt64("FirstAnimOffset");
            bw.WriteInt64(1);
            bw.WriteInt64(0x90);
            bw.WriteInt32(ID);
            bw.WriteInt32(ID);
            bw.WriteInt64(0x50);
            bw.WriteInt64(0);
            bw.WriteInt64(0xB0);
            bw.ReserveInt64("SkeletonName");
            bw.ReserveInt64("SibName");
            bw.WriteInt64(0);
            bw.WriteInt64(0);

            bw.FillInt64("SkeletonName", bw.Position);
            bw.WriteUTF16(SkeletonName, true);
            bw.Pad(0x10);

            bw.FillInt64("SibName", bw.Position);
            bw.WriteUTF16(SibName, true);
            bw.Pad(0x10);

            Animations.Sort((a1, a2) => a1.ID.CompareTo(a2.ID));

            bw.FillInt64("AnimsOffset", bw.Position);
            var animOffsets = new List <long>(Animations.Count);

            for (int i = 0; i < Animations.Count; i++)
            {
                animOffsets.Add(bw.Position);
                Animations[i].WriteHeader(bw, i);
            }

            bw.FillInt64("AnimGroupsOffset", bw.Position);
            bw.ReserveInt64("AnimGroupsCount");
            bw.ReserveInt64("AnimGroupsOffset");
            int  groupCount = 0;
            long groupStart = bw.Position;

            for (int i = 0; i < Animations.Count; i++)
            {
                int firstIndex = i;
                bw.WriteInt32((int)Animations[i].ID);
                while (i < Animations.Count - 1 && Animations[i + 1].ID == Animations[i].ID + 1)
                {
                    i++;
                }
                bw.WriteInt32((int)Animations[i].ID);
                bw.WriteInt64(animOffsets[firstIndex]);
                groupCount++;
            }
            bw.FillInt64("AnimGroupsCount", groupCount);
            if (groupCount == 0)
            {
                bw.FillInt64("AnimGroupsOffset", 0);
            }
            else
            {
                bw.FillInt64("AnimGroupsOffset", groupStart);
            }

            bw.FillInt64("FirstAnimOffset", bw.Position);
            for (int i = 0; i < Animations.Count; i++)
            {
                Animations[i].WriteBody(bw, i);
            }

            for (int i = 0; i < Animations.Count; i++)
            {
                Animations[i].WriteAnimFile(bw, i);

                long timeStart = bw.Position;
                Animations[i].WriteTimes(bw, i);

                var eventHeaderOffsets = Animations[i].WriteEventHeaders(bw, i, timeStart);

                Animations[i].WriteEventData(bw, i);

                Animations[i].WriteEventGroupHeaders(bw, i);

                Animations[i].WriteEventGroupData(bw, i, eventHeaderOffsets);
            }

            bw.FillInt32("FileSize", (int)bw.Position);
        }
Beispiel #6
0
        internal override void Write(BinaryWriterEx bw)
        {
            bw.BigEndian = false;

            bw.WriteByte(0);
            bw.WriteByte(0);
            bw.WriteByte((byte)(Long ? 2 : 1));
            bw.WriteByte(0);

            bw.ReserveInt32("FileSize");
            bw.WriteInt32(1);
            bw.ReserveInt32("GroupCount");
            bw.WriteInt32(Entries.Count);

            if (Long)
            {
                bw.WriteInt32(0xFF);
            }

            if (Long)
            {
                bw.ReserveInt64("StringOffsets");
            }
            else
            {
                bw.ReserveInt32("StringOffsets");
            }

            bw.WriteInt32(0);
            bw.WriteInt32(0);

            int groupCount = 0;

            Entries.Sort((e1, e2) => e1.ID.CompareTo(e2.ID));
            for (int i = 0; i < Entries.Count; i++)
            {
                bw.WriteInt32(i);
                bw.WriteInt32(Entries[i].ID);
                while (i < Entries.Count - 1 && Entries[i + 1].ID == Entries[i].ID + 1)
                {
                    i++;
                }
                bw.WriteInt32(Entries[i].ID);

                if (Long)
                {
                    bw.WriteInt32(0);
                }

                groupCount++;
            }
            bw.FillInt32("GroupCount", groupCount);

            if (Long)
            {
                bw.FillInt64("StringOffsets", bw.Position);
            }
            else
            {
                bw.FillInt32("StringOffsets", (int)bw.Position);
            }

            for (int i = 0; i < Entries.Count; i++)
            {
                if (Long)
                {
                    bw.ReserveInt64($"StringOffset{i}");
                }
                else
                {
                    bw.ReserveInt32($"StringOffset{i}");
                }
            }

            for (int i = 0; i < Entries.Count; i++)
            {
                string text = Entries[i].Text;

                if (Long)
                {
                    bw.FillInt64($"StringOffset{i}", text == null ? 0 : bw.Position);
                }
                else
                {
                    bw.FillInt64($"StringOffset{i}", text == null ? 0 : (int)bw.Position);
                }

                if (text != null)
                {
                    bw.WriteUTF16(Entries[i].Text, true);
                }
            }

            bw.FillInt32("FileSize", (int)bw.Position);
        }
Beispiel #7
0
        /// <summary>
        /// Serializes file data to a stream.
        /// </summary>
        protected override void Write(BinaryWriterEx bw)
        {
            if (AppliedParamdef == null)
            {
                throw new InvalidOperationException("Params cannot be written without applying a paramdef.");
            }

            bw.BigEndian = BigEndian;
            void WriteFormat()
            {
                bw.WriteByte((byte)(BigEndian ? 0xFF : 0x00));
                bw.WriteByte(Format2D);
                bw.WriteByte(Format2E);
                bw.WriteByte(Format2F);
            }

            // DeS, DS1
            if ((Format2D & 0x7F) < 3)
            {
                bw.ReserveUInt32("StringsOffset");
                bw.ReserveUInt16("DataStart");
                bw.WriteInt16(Unk06);
                bw.WriteInt16(Unk08);
                bw.WriteUInt16((ushort)Rows.Count);
                bw.WriteFixStr(ParamType, 0x20, (byte)((Format2D & 0x7F) < 2 ? 0x20 : 0x00));
                WriteFormat();
            }
            // DS2
            else if ((Format2D & 0x7F) == 3)
            {
                bw.ReserveUInt32("StringsOffset");
                bw.WriteInt16(0);
                bw.WriteInt16(Unk06);
                bw.WriteInt16(Unk08);
                bw.WriteUInt16((ushort)Rows.Count);
                bw.WriteFixStr(ParamType, 0x20, 0x20);
                WriteFormat();
                bw.ReserveUInt32("DataStart");
                bw.WriteInt32(0);
                bw.WriteInt32(0);
                bw.WriteInt32(0);
            }
            // SotFS, BB
            else if ((Format2D & 0x7F) == 4)
            {
                bw.ReserveUInt32("StringsOffset");
                bw.WriteInt16(0);
                bw.WriteInt16(Unk06);
                bw.WriteInt16(Unk08);
                bw.WriteUInt16((ushort)Rows.Count);
                bw.WriteFixStr(ParamType, 0x20, 0x00);
                WriteFormat();
                bw.ReserveInt64("DataStart");
                bw.WriteInt64(0);
            }
            // DS3, SDT
            else
            {
                bw.ReserveUInt32("StringsOffset");
                bw.WriteInt16(0);
                bw.WriteInt16(Unk06);
                bw.WriteInt16(Unk08);
                bw.WriteUInt16((ushort)Rows.Count);
                bw.WriteInt32(0);
                bw.ReserveInt64("IDOffset");
                bw.WritePattern(0x14, 0x00);
                WriteFormat();
                bw.ReserveInt64("DataStart");
                bw.WriteInt64(0);
            }

            for (int i = 0; i < Rows.Count; i++)
            {
                Rows[i].WriteHeader(bw, Format2D, i);
            }

            if ((Format2D & 0x7F) < 2)
            {
                bw.WritePattern(0x20, 0x00);
            }
            if ((Format2D & 0x7F) < 3)
            {
                bw.FillUInt16("DataStart", (ushort)bw.Position);
            }
            else if ((Format2D & 0x7F) == 3)
            {
                bw.FillUInt32("DataStart", (uint)bw.Position);
            }
            else
            {
                bw.FillInt64("DataStart", bw.Position);
            }

            for (int i = 0; i < Rows.Count; i++)
            {
                Rows[i].WriteCells(bw, Format2D, i);
            }

            bw.FillUInt32("StringsOffset", (uint)bw.Position);

            if ((Format2D & 0x7F) > 4)
            {
                bw.FillInt64("IDOffset", bw.Position);
                bw.WriteASCII(ParamType, true);
            }

            for (int i = 0; i < Rows.Count; i++)
            {
                Rows[i].WriteName(bw, Format2D, Format2E, i);
            }
            // DeS and BB sometimes (but not always) include some useless padding here
        }
Beispiel #8
0
        /// <summary>
        /// Serializes file data to a stream.
        /// </summary>
        protected override void Write(BinaryWriterEx bw)
        {
            if (AppliedParamdef == null)
            {
                throw new InvalidOperationException("Params cannot be written without applying a paramdef.");
            }

            bw.BigEndian = BigEndian;

            bw.ReserveUInt32("StringsOffset");
            if (Format2D.HasFlag(FormatFlags1.Flag01) && Format2D.HasFlag(FormatFlags1.IntDataOffset) || Format2D.HasFlag(FormatFlags1.LongDataOffset))
            {
                bw.WriteInt16(0);
            }
            else
            {
                bw.ReserveUInt16("DataStart");
            }
            bw.WriteInt16(Unk06);
            bw.WriteInt16(ParamdefDataVersion);
            bw.WriteUInt16((ushort)Rows.Count);
            if (Format2D.HasFlag(FormatFlags1.OffsetParamType))
            {
                bw.WriteInt32(0);
                bw.ReserveInt64("ParamTypeOffset");
                bw.WritePattern(0x14, 0x00);
            }
            else
            {
                // This padding heuristic isn't completely accurate, not that it matters
                bw.WriteFixStr(ParamType, 0x20, (byte)(Format2D.HasFlag(FormatFlags1.Flag01) ? 0x20 : 0x00));
            }
            bw.WriteByte((byte)(BigEndian ? 0xFF : 0x00));
            bw.WriteByte((byte)Format2D);
            bw.WriteByte((byte)Format2E);
            bw.WriteByte(ParamdefFormatVersion);
            if (Format2D.HasFlag(FormatFlags1.Flag01) && Format2D.HasFlag(FormatFlags1.IntDataOffset))
            {
                bw.ReserveUInt32("DataStart");
                bw.WriteInt32(0);
                bw.WriteInt32(0);
                bw.WriteInt32(0);
            }
            else if (Format2D.HasFlag(FormatFlags1.LongDataOffset))
            {
                bw.ReserveInt64("DataStart");
                bw.WriteInt64(0);
            }

            for (int i = 0; i < Rows.Count; i++)
            {
                Rows[i].WriteHeader(bw, this, i);
            }

            // This is probably pretty stupid
            if (Format2D == FormatFlags1.Flag01)
            {
                bw.WritePattern(0x20, 0x00);
            }

            if (Format2D.HasFlag(FormatFlags1.Flag01) && Format2D.HasFlag(FormatFlags1.IntDataOffset))
            {
                bw.FillUInt32("DataStart", (uint)bw.Position);
            }
            else if (Format2D.HasFlag(FormatFlags1.LongDataOffset))
            {
                bw.FillInt64("DataStart", bw.Position);
            }
            else
            {
                bw.FillUInt16("DataStart", (ushort)bw.Position);
            }

            for (int i = 0; i < Rows.Count; i++)
            {
                Rows[i].WriteCells(bw, this, i);
            }

            bw.FillUInt32("StringsOffset", (uint)bw.Position);

            if (Format2D.HasFlag(FormatFlags1.OffsetParamType))
            {
                bw.FillInt64("ParamTypeOffset", bw.Position);
                bw.WriteASCII(ParamType, true);
            }

            for (int i = 0; i < Rows.Count; i++)
            {
                Rows[i].WriteName(bw, this, i);
            }
            // DeS and BB sometimes (but not always) include some useless padding here
        }
Beispiel #9
0
        internal override void Write(BinaryWriterEx bw)
        {
            bw.BigEndian = BigEndian;
            bool wide = Version == FMGVersion.DarkSouls3;

            bw.WriteByte(0);
            bw.WriteBoolean(bw.BigEndian);
            bw.WriteByte((byte)Version);
            bw.WriteByte(0);

            bw.ReserveInt32("FileSize");
            bw.WriteByte(1);
            bw.WriteByte((byte)(Version == FMGVersion.DemonsSouls ? 0xFF : 0x00));
            bw.WriteByte(0);
            bw.WriteByte(0);
            bw.ReserveInt32("GroupCount");
            bw.WriteInt32(Entries.Count);

            if (wide)
            {
                bw.WriteInt32(0xFF);
            }

            if (wide)
            {
                bw.ReserveInt64("StringOffsets");
            }
            else
            {
                bw.ReserveInt32("StringOffsets");
            }

            if (wide)
            {
                bw.WriteInt64(0);
            }
            else
            {
                bw.WriteInt32(0);
            }

            int groupCount = 0;

            Entries.Sort((e1, e2) => e1.ID.CompareTo(e2.ID));
            for (int i = 0; i < Entries.Count; i++)
            {
                bw.WriteInt32(i);
                bw.WriteInt32(Entries[i].ID);
                while (i < Entries.Count - 1 && Entries[i + 1].ID == Entries[i].ID + 1)
                {
                    i++;
                }
                bw.WriteInt32(Entries[i].ID);

                if (wide)
                {
                    bw.WriteInt32(0);
                }

                groupCount++;
            }
            bw.FillInt32("GroupCount", groupCount);

            if (wide)
            {
                bw.FillInt64("StringOffsets", bw.Position);
            }
            else
            {
                bw.FillInt32("StringOffsets", (int)bw.Position);
            }

            for (int i = 0; i < Entries.Count; i++)
            {
                if (wide)
                {
                    bw.ReserveInt64($"StringOffset{i}");
                }
                else
                {
                    bw.ReserveInt32($"StringOffset{i}");
                }
            }

            for (int i = 0; i < Entries.Count; i++)
            {
                string text = Entries[i].Text;

                if (wide)
                {
                    bw.FillInt64($"StringOffset{i}", text == null ? 0 : bw.Position);
                }
                else
                {
                    bw.FillInt32($"StringOffset{i}", text == null ? 0 : (int)bw.Position);
                }

                if (text != null)
                {
                    bw.WriteUTF16(Entries[i].Text, true);
                }
            }

            bw.FillInt32("FileSize", (int)bw.Position);
        }
Beispiel #10
0
            internal void Write(BinaryWriterEx bw, List <File> files)
            {
                bw.BigEndian = BigEndian;
                bw.WriteASCII("BHF4");
                bw.WriteBoolean(Flag1);
                bw.WriteBoolean(Flag2);
                bw.WriteByte(0);
                bw.WriteByte(0);
                bw.WriteInt32(0x10000);
                bw.WriteInt32(files.Count);
                bw.WriteInt64(0x40);
                bw.WriteASCII(Timestamp.PadRight(8, '\0'));
                if (Format == 0x0C || Format == 0x30)
                {
                    bw.WriteInt64(0x18);
                }
                else if (Format == 0x2E || Format == 0x74)
                {
                    bw.WriteInt64(0x24);
                }
                else if (Format == 0x3E)
                {
                    bw.WriteInt64(0x28);
                }
                bw.WriteInt64(0);

                bw.WriteBoolean(Unicode);
                bw.WriteByte(Format);
                bw.WriteByte(Extended);
                bw.WriteByte(0);

                bw.WriteInt32(0);
                if (Extended == 4)
                {
                    bw.ReserveInt64("HashGroups");
                }
                else
                {
                    bw.WriteInt64(0);
                }

                for (int i = 0; i < files.Count; i++)
                {
                    FileHeader.Write(bw, files[i], i, Format);
                }

                for (int i = 0; i < files.Count; i++)
                {
                    File file = files[i];
                    bw.FillInt32($"FileName{i}", (int)bw.Position);
                    if (Unicode)
                    {
                        bw.WriteUTF16(file.Name, true);
                    }
                    else
                    {
                        bw.WriteShiftJIS(file.Name, true);
                    }
                }

                if (Extended == 4)
                {
                    uint groupCount = 0;
                    for (uint p = (uint)files.Count / 7; p <= 100000; p++)
                    {
                        if (Util.IsPrime(p))
                        {
                            groupCount = p;
                            break;
                        }
                    }

                    if (groupCount == 0)
                    {
                        throw new InvalidOperationException("Hash group count not determined in BXF4.");
                    }

                    var hashLists = new List <PathHash> [groupCount];
                    for (int i = 0; i < groupCount; i++)
                    {
                        hashLists[i] = new List <PathHash>();
                    }

                    for (int i = 0; i < files.Count; i++)
                    {
                        var  pathHash = new PathHash(i, files[i].Name);
                        uint group    = pathHash.Hash % groupCount;
                        hashLists[group].Add(pathHash);
                    }

                    for (int i = 0; i < groupCount; i++)
                    {
                        hashLists[i].Sort((ph1, ph2) => ph1.Hash.CompareTo(ph2.Hash));
                    }

                    var hashGroups = new List <HashGroup>();
                    var pathHashes = new List <PathHash>();

                    int count = 0;
                    foreach (List <PathHash> hashList in hashLists)
                    {
                        int index = count;
                        foreach (PathHash pathHash in hashList)
                        {
                            pathHashes.Add(pathHash);
                            count++;
                        }

                        hashGroups.Add(new HashGroup(index, count - index));
                    }

                    bw.Pad(0x8);
                    bw.FillInt64("HashGroups", bw.Position);
                    bw.ReserveInt64("PathHashes");
                    bw.WriteUInt32(groupCount);
                    bw.WriteInt32(0x00080810);

                    foreach (HashGroup hashGroup in hashGroups)
                    {
                        hashGroup.Write(bw);
                    }

                    // No padding after section 1
                    bw.FillInt64("PathHashes", bw.Position);
                    foreach (PathHash pathHash in pathHashes)
                    {
                        pathHash.Write(bw);
                    }
                }
            }
Beispiel #11
0
            internal override void Write(BinaryWriterEx bw, int id)
            {
                long start = bw.Position;

                bw.ReserveInt64("NameOffset");
                bw.WriteUInt32((uint)Type);
                bw.WriteInt32(id);
                bw.WriteUInt32((uint)Shape.Type);
                bw.WriteVector3(Position);
                bw.WriteVector3(Rotation);
                bw.WriteInt32(Unk2C);
                bw.ReserveInt64("BaseDataOffset1");
                bw.ReserveInt64("BaseDataOffset2");
                bw.WriteInt32(-1);
                bw.WriteInt32(MapStudioLayer);
                bw.ReserveInt64("ShapeDataOffset");
                bw.ReserveInt64("BaseDataOffset3");
                bw.ReserveInt64("TypeDataOffset");

                bw.FillInt64("NameOffset", bw.Position - start);
                bw.WriteUTF16(Name, true);
                bw.Pad(4);

                bw.FillInt64("BaseDataOffset1", bw.Position - start);
                bw.WriteInt16((short)UnkA.Count);
                bw.WriteInt16s(UnkA);
                bw.Pad(4);

                bw.FillInt64("BaseDataOffset2", bw.Position - start);
                bw.WriteInt16((short)UnkB.Count);
                bw.WriteInt16s(UnkB);
                bw.Pad(8);

                if (Shape.HasShapeData)
                {
                    bw.FillInt64("ShapeDataOffset", bw.Position - start);
                    Shape.WriteShapeData(bw);
                }
                else
                {
                    bw.FillInt64("ShapeDataOffset", 0);
                }

                bw.FillInt64("BaseDataOffset3", bw.Position - start);
                bw.WriteInt32(UnkC00);
                bw.WriteInt32(UnkC04);

                if (HasTypeData)
                {
                    if (Type == RegionType.Region23 || Type == RegionType.PartsGroup || Type == RegionType.AutoDrawGroup)
                    {
                        bw.Pad(8);
                    }

                    bw.FillInt64("TypeDataOffset", bw.Position - start);
                    WriteTypeData(bw);
                }
                else
                {
                    bw.FillInt64("TypeDataOffset", 0);
                }
                bw.Pad(8);
            }
Beispiel #12
0
            internal void Write(BinaryWriterEx bw)
            {
                long start = bw.Position;

                bw.ReserveInt64("DescOffset");
                bw.ReserveInt64("NameOffset");
                bw.WriteInt32(ModelLocalID);
                bw.WriteUInt32((uint)Type);
                bw.WriteInt32(ID);
                bw.WriteInt32(modelIndex);
                bw.ReserveInt64("PlaceholderOffset");
                bw.WriteVector3(Position);
                bw.WriteVector3(Rotation);
                bw.WriteVector3(Scale);

                bw.WriteUInt32s(DrawGroups);
                bw.WriteUInt32s(DispGroups);
                bw.WriteUInt32s(BackreadGroups);
                bw.WriteInt32(UnkFA4);

                bw.ReserveInt64("BaseDataOffset");
                bw.ReserveInt64("TypeDataOffset");
                bw.ReserveInt64("UnkOffset1");
                bw.ReserveInt64("UnkOffset2");

                bw.FillInt64("DescOffset", bw.Position - start);
                bw.WriteUTF16(Description, true);
                bw.FillInt64("NameOffset", bw.Position - start);
                bw.WriteUTF16(Name, true);
                if (Placeholder == null)
                {
                    bw.FillInt64("PlaceholderOffset", 0);
                }
                else
                {
                    bw.FillInt64("PlaceholderOffset", bw.Position - start);
                    bw.WriteUTF16(Placeholder, true);
                }
                bw.Pad(8);

                bw.FillInt64("BaseDataOffset", bw.Position - start);
                bw.WriteInt32(EventEntityID);

                bw.WriteSByte(OldLightID);
                bw.WriteSByte(OldFogID);
                bw.WriteSByte(OldScatterID);
                bw.WriteSByte(OldLensFlareID);

                bw.WriteInt32(0);

                bw.WriteSByte(OldLanternID);
                bw.WriteSByte(OldLodParamID);
                bw.WriteSByte(UnkB0E);
                bw.WriteBoolean(OldIsShadowDest);

                bw.FillInt64("TypeDataOffset", bw.Position - start);
                if (UnkOffset1Delta == 0)
                {
                    bw.FillInt64("UnkOffset1", 0);
                }
                else
                {
                    bw.FillInt64("UnkOffset1", bw.Position - start + UnkOffset1Delta);
                }

                if (UnkOffset2Delta == 0)
                {
                    bw.FillInt64("UnkOffset2", 0);
                }
                else
                {
                    bw.FillInt64("UnkOffset2", bw.Position - start + UnkOffset2Delta);
                }

                WriteSpecific(bw);
            }
Beispiel #13
0
            internal void Write(BinaryWriterEx bw, PARAMDEF def, int index)
            {
                if (def.FormatVersion >= 202)
                {
                    bw.ReserveInt64($"DisplayNameOffset{index}");
                }
                else if (def.Unicode)
                {
                    bw.WriteFixStrW(DisplayName, 0x40, (byte)(def.FormatVersion >= 104 ? 0x00 : 0x20));
                }
                else
                {
                    bw.WriteFixStr(DisplayName, 0x40, (byte)(def.FormatVersion >= 104 ? 0x00 : 0x20));
                }

                byte padding = (byte)(def.FormatVersion >= 200 ? 0x00 : 0x20);

                bw.WriteFixStr(DisplayType.ToString(), 8, padding);
                bw.WriteFixStr(DisplayFormat, 8, padding);
                bw.WriteSingle(Default);
                bw.WriteSingle(Minimum);
                bw.WriteSingle(Maximum);
                bw.WriteSingle(Increment);
                bw.WriteInt32((int)EditFlags);
                bw.WriteInt32(ParamUtil.GetValueSize(DisplayType) * (ParamUtil.IsArrayType(DisplayType) ? ArrayLength : 1));

                if (def.FormatVersion >= 200)
                {
                    bw.ReserveInt64($"DescriptionOffset{index}");
                }
                else
                {
                    bw.ReserveInt32($"DescriptionOffset{index}");
                }

                if (def.FormatVersion >= 202)
                {
                    bw.ReserveInt64($"InternalTypeOffset{index}");
                }
                else
                {
                    bw.WriteFixStr(InternalType, 0x20, padding);
                }

                if (def.FormatVersion >= 202)
                {
                    bw.ReserveInt64($"InternalNameOffset{index}");
                }
                else if (def.FormatVersion >= 102)
                {
                    bw.WriteFixStr(MakeInternalName(), 0x20, padding);
                }

                if (def.FormatVersion >= 104)
                {
                    bw.WriteInt32(SortID);
                }

                if (def.FormatVersion >= 200)
                {
                    bw.WriteInt32(0);
                    bw.ReserveInt64($"UnkB8Offset{index}");
                    bw.ReserveInt64($"UnkC0Offset{index}");
                    bw.ReserveInt64($"UnkC8Offset{index}");
                }
            }
Beispiel #14
0
        public static void Write(BinaryWriterEx bw, List <BinderFileHeader> files)
        {
            uint groupCount = 0;

            for (uint p = (uint)files.Count / 7; p <= 100000; p++)
            {
                if (SFUtil.IsPrime(p))
                {
                    groupCount = p;
                    break;
                }
            }

            if (groupCount == 0)
            {
                throw new InvalidOperationException("Could not determine hash group count.");
            }

            var hashLists = new List <PathHash> [groupCount];

            for (int i = 0; i < groupCount; i++)
            {
                hashLists[i] = new List <PathHash>();
            }

            for (int i = 0; i < files.Count; i++)
            {
                var  pathHash = new PathHash(i, files[i].Name);
                uint group    = pathHash.Hash % groupCount;
                hashLists[group].Add(pathHash);
            }

            for (int i = 0; i < groupCount; i++)
            {
                hashLists[i].Sort((ph1, ph2) => ph1.Hash.CompareTo(ph2.Hash));
            }

            var hashGroups = new List <HashGroup>();
            var pathHashes = new List <PathHash>();

            int count = 0;

            foreach (List <PathHash> hashList in hashLists)
            {
                int index = count;
                foreach (PathHash pathHash in hashList)
                {
                    pathHashes.Add(pathHash);
                    count++;
                }

                hashGroups.Add(new HashGroup(index, count - index));
            }

            bw.ReserveInt64("HashesOffset");
            bw.WriteUInt32(groupCount);

            bw.WriteByte(0x10);
            bw.WriteByte(8);
            bw.WriteByte(8);
            bw.WriteByte(0);

            foreach (HashGroup hashGroup in hashGroups)
            {
                hashGroup.Write(bw);
            }

            bw.FillInt64("HashesOffset", bw.Position);
            foreach (PathHash pathHash in pathHashes)
            {
                pathHash.Write(bw);
            }
        }
Beispiel #15
0
        internal override void Write(BinaryWriterEx bw)
        {
            if (layout == null)
            {
                throw new InvalidOperationException("Params cannot be written without a layout.");
            }

            Rows.Sort((r1, r2) => r1.ID.CompareTo(r2.ID));

            bw.BigEndian = false;

            bw.ReserveInt32("NameOffset");
            bw.WriteInt16(0);
            bw.WriteInt16(Unk1);
            bw.WriteInt16(Unk2);
            bw.WriteUInt16((ushort)Rows.Count);

            if (FixStrID)
            {
                bw.WriteFixStr(ID, 0x20);
            }
            else
            {
                bw.WriteInt32(0);
                bw.ReserveInt32("IDOffset");
                bw.WriteInt32(0);
                bw.WriteInt32(0);
                bw.WriteInt32(0);
                bw.WriteInt32(0);
                bw.WriteInt32(0);
                bw.WriteInt32(0);
            }

            bw.WriteByte(0);
            bw.WriteByte(Unk3);
            bw.WriteByte(Unk4);
            bw.WriteByte(0);

            bw.ReserveInt64("DataStart");
            bw.WriteInt32(0);
            bw.WriteInt32(0);

            for (int i = 0; i < Rows.Count; i++)
            {
                Rows[i].WriteHeader(bw, i);
            }

            bw.FillInt64("DataStart", bw.Position);

            for (int i = 0; i < Rows.Count; i++)
            {
                Rows[i].WriteCells(bw, i, layout);
            }

            bw.FillInt32("NameOffset", (int)bw.Position);
            if (FixStrID)
            {
                if (Unk4 == 6)
                {
                    bw.WriteShiftJIS(Name, true);
                }
                else if (Unk4 == 7)
                {
                    bw.WriteUTF16(Name, true);
                }
            }
            else
            {
                bw.WriteShiftJIS(Name, true);
                bw.FillInt32("IDOffset", (int)bw.Position);
                bw.WriteASCII(ID, true);
            }

            for (int i = 0; i < Rows.Count; i++)
            {
                Rows[i].WriteName(bw, i, Unk4);
            }
        }
Beispiel #16
0
        /// <summary>
        /// Writes BND4 data to a BinaryWriterEx.
        /// </summary>
        internal override void Write(BinaryWriterEx bw)
        {
            bw.BigEndian = BigEndian;

            bw.WriteASCII("BND4");
            bw.WriteBoolean(Flag1);
            bw.WriteBoolean(Flag2);
            bw.WriteByte(0);
            bw.WriteByte(0);

            bw.WriteInt32(0x10000);
            bw.WriteInt32(Files.Count);
            bw.WriteInt64(0x40);
            bw.WriteFixStr(Timestamp, 8);
            if (Format == 0x0C)
            {
                bw.WriteInt64(0x18);
            }
            else if (Format == 0x70)
            {
                bw.WriteInt64(0x1C);
            }
            else
            {
                bw.WriteInt64(0x24);
            }
            bw.ReserveInt64("DataStart");

            bw.WriteBoolean(Unicode);
            bw.WriteByte(Format);
            bw.WriteByte(Extended);
            bw.WriteByte(0);

            bw.WriteInt32(0);
            if (Extended == 4)
            {
                bw.ReserveInt64("HashGroups");
            }
            else
            {
                bw.WriteInt64(0);
            }

            for (int i = 0; i < Files.Count; i++)
            {
                Files[i].Write(bw, i, Format);
            }

            for (int i = 0; i < Files.Count; i++)
            {
                File file = Files[i];
                bw.FillInt32($"FileName{i}", (int)bw.Position);
                if (Unicode)
                {
                    bw.WriteUTF16(file.Name, true);
                }
                else
                {
                    bw.WriteShiftJIS(file.Name, true);
                }
            }

            if (Extended == 4)
            {
                uint groupCount = 0;
                for (uint p = (uint)Files.Count / 7; p <= 100000; p++)
                {
                    if (SFUtil.IsPrime(p))
                    {
                        groupCount = p;
                        break;
                    }
                }

                if (groupCount == 0)
                {
                    throw new InvalidOperationException("Hash group count not determined in BND4.");
                }

                var hashLists = new List <PathHash> [groupCount];
                for (int i = 0; i < groupCount; i++)
                {
                    hashLists[i] = new List <PathHash>();
                }

                for (int i = 0; i < Files.Count; i++)
                {
                    var  pathHash = new PathHash(i, Files[i].Name);
                    uint group    = pathHash.Hash % groupCount;
                    hashLists[group].Add(pathHash);
                }

                for (int i = 0; i < groupCount; i++)
                {
                    hashLists[i].Sort((ph1, ph2) => ph1.Hash.CompareTo(ph2.Hash));
                }

                var hashGroups = new List <HashGroup>();
                var pathHashes = new List <PathHash>();

                int count = 0;
                foreach (List <PathHash> hashList in hashLists)
                {
                    int index = count;
                    foreach (PathHash pathHash in hashList)
                    {
                        pathHashes.Add(pathHash);
                        count++;
                    }

                    hashGroups.Add(new HashGroup(index, count - index));
                }

                bw.Pad(0x8);
                bw.FillInt64("HashGroups", bw.Position);
                bw.ReserveInt64("PathHashes");
                bw.WriteUInt32(groupCount);
                bw.WriteInt32(0x00080810);

                foreach (HashGroup hashGroup in hashGroups)
                {
                    hashGroup.Write(bw);
                }

                // No padding after section 1
                bw.FillInt64("PathHashes", bw.Position);
                foreach (PathHash pathHash in pathHashes)
                {
                    pathHash.Write(bw);
                }
            }

            bw.FillInt64("DataStart", bw.Position);
            for (int i = 0; i < Files.Count; i++)
            {
                File file = Files[i];
                if (file.Bytes.LongLength > 0)
                {
                    bw.Pad(0x10);
                }

                bw.FillInt32($"FileData{i}", (int)bw.Position);

                byte[] bytes          = file.Bytes;
                int    compressedSize = bytes.Length;

                if (file.Flags == 0x03 || file.Flags == 0xC0)
                {
                    compressedSize = SFUtil.WriteZlib(bw, 0x9C, bytes);
                }
                else
                {
                    bw.WriteBytes(bytes);
                }

                bw.FillInt64($"CompressedSize{i}", bytes.Length);
            }
        }
Beispiel #17
0
 internal void WriteHeader(BinaryWriterEx bw, int i)
 {
     bw.WriteInt64(ID);
     bw.ReserveInt64($"RowOffset{i}");
     bw.ReserveInt64($"NameOffset{i}");
 }
Beispiel #18
0
        /// <summary>
        /// Serializes file data to a stream.
        /// </summary>
        protected override void Write(BinaryWriterEx bw)
        {
            bw.BigEndian = BigEndian;

            bw.ReserveInt32("FileSize");
            bw.WriteInt16((short)(FormatVersion >= 200 ? 0xFF : 0x30));
            bw.WriteInt16(DataVersion);
            bw.WriteInt16((short)Fields.Count);

            if (FormatVersion == 101)
            {
                bw.WriteInt16(0x8C);
            }
            else if (FormatVersion == 102)
            {
                bw.WriteInt16(0xAC);
            }
            else if (FormatVersion == 103)
            {
                bw.WriteInt16(0x6C);
            }
            else if (FormatVersion == 104)
            {
                bw.WriteInt16(0xB0);
            }
            else if (FormatVersion == 201)
            {
                bw.WriteInt16(0xD0);
            }
            else if (FormatVersion == 202)
            {
                bw.WriteInt16(0x68);
            }

            if (FormatVersion >= 202)
            {
                bw.WriteInt32(0);
                bw.ReserveInt64("ParamTypeOffset");
                bw.WriteInt64(0);
                bw.WriteInt64(0);
                bw.WriteInt32(0);
            }
            else
            {
                bw.WriteFixStr(ParamType, 0x20, (byte)(FormatVersion >= 200 ? 0x00 : 0x20));
            }

            bw.WriteSByte((sbyte)(BigEndian ? -1 : 0));
            bw.WriteBoolean(Unicode);
            bw.WriteInt16(FormatVersion);
            if (FormatVersion >= 200)
            {
                bw.WriteInt64(0x38);
            }

            for (int i = 0; i < Fields.Count; i++)
            {
                Fields[i].Write(bw, this, i);
            }

            if (FormatVersion >= 202)
            {
                bw.FillInt64("ParamTypeOffset", bw.Position);
                bw.WriteShiftJIS(ParamType, true);
            }

            long fieldStringsStart   = bw.Position;
            var  sharedStringOffsets = new Dictionary <string, long>();

            for (int i = 0; i < Fields.Count; i++)
            {
                Fields[i].WriteStrings(bw, this, i, sharedStringOffsets);
            }

            if (FormatVersion >= 104 && FormatVersion < 202)
            {
                long fieldStringsLength = bw.Position - fieldStringsStart;
                if (fieldStringsLength % 0x10 != 0)
                {
                    bw.WritePattern((int)(0x10 - fieldStringsLength % 0x10), 0x00);
                }
            }
            else
            {
                if (FormatVersion >= 202 && bw.Position % 0x10 == 0)
                {
                    bw.WritePattern(0x10, 0x00);
                }
                bw.Pad(0x10);
            }
            bw.FillInt32("FileSize", (int)bw.Position);
        }