예제 #1
0
            internal void Write(BinaryWriterEx bw, MQBVersion version, Dictionary <Disposition, long> offsetsByDispos, int cutIndex, List <CustomData> allCustomData, List <long> customDataValueOffsets)
            {
                int disposCount = Timelines.Sum(g => g.Dispositions.Count);

                bw.WriteFixStrW(Name, 0x40, 0x00);
                bw.WriteInt32(disposCount);
                bw.WriteInt32(Unk44);
                bw.WriteInt32(Duration);
                bw.WriteInt32(0);

                bw.WriteInt32(Timelines.Count);
                if (version == MQBVersion.DarkSouls2Scholar)
                {
                    bw.WriteInt32(0);
                }
                bw.ReserveVarint($"TimelinesOffset{cutIndex}");
                if (version != MQBVersion.DarkSouls2Scholar)
                {
                    bw.WriteInt64(0);
                }

                foreach (Timeline timeline in Timelines)
                {
                    timeline.WriteDispositions(bw, offsetsByDispos, allCustomData, customDataValueOffsets);
                }
            }
예제 #2
0
            internal void Write(BinaryWriterEx bw, PARAMDEF def, int index)
            {
                if (def.Unicode)
                {
                    bw.WriteFixStrW(DisplayName, 0x40, (byte)(def.Version >= 104 ? 0x00 : 0x20));
                }
                else
                {
                    bw.WriteFixStr(DisplayName, 0x40, (byte)(def.Version >= 104 ? 0x00 : 0x20));
                }

                byte padding = (byte)(def.Version >= 201 ? 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.Version >= 201)
                {
                    bw.ReserveInt64($"DescriptionOffset{index}");
                }
                else
                {
                    bw.ReserveInt32($"DescriptionOffset{index}");
                }

                bw.WriteFixStr(InternalType, 0x20, padding);

                if (def.Version >= 102)
                {
                    string internalName = InternalName;
                    // This is accurate except for "hasTarget : 1" in SpEffect
                    if (BitSize != -1)
                    {
                        internalName = $"{internalName}:{BitSize}";
                    }
                    // BB is not consistent about including [1] or not, but PTDE always does
                    else if (ParamUtil.IsArrayType(DisplayType))
                    {
                        internalName = $"{internalName}[{ArrayLength}]";
                    }
                    bw.WriteFixStr(internalName, 0x20, padding);
                }

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

                if (def.Version >= 201)
                {
                    bw.WritePattern(0x1C, 0x00);
                }
            }
예제 #3
0
            internal void Write(BinaryWriterEx bw, int resourceIndex, List <CustomData> allCustomData, List <long> customDataValueOffsets)
            {
                bw.WriteFixStrW(Name, 0x40, 0x00);
                bw.WriteInt32(ParentIndex);
                bw.WriteInt32(resourceIndex);
                bw.WriteInt32(Unk48);
                bw.WriteInt32(CustomData.Count);

                foreach (CustomData customData in CustomData)
                {
                    customData.Write(bw, allCustomData, customDataValueOffsets);
                }
            }
예제 #4
0
            internal void Write(BinaryWriterEx bw, PARAMDEF def, int index)
            {
                if (def.Unicode)
                {
                    bw.WriteFixStrW(DisplayName, 0x40, (byte)(def.Version >= 104 ? 0x00 : 0x20));
                }
                else
                {
                    bw.WriteFixStr(DisplayName, 0x40, (byte)(def.Version >= 104 ? 0x00 : 0x20));
                }

                byte padding = (byte)(def.Version >= 201 ? 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(ByteCount);

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

                bw.WriteFixStr(InternalType, 0x20, padding);

                if (def.Version >= 102)
                {
                    bw.WriteFixStr(InternalName, 0x20, padding);
                }

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

                if (def.Version >= 201)
                {
                    bw.WritePattern(0x1C, 0x00);
                }
            }
예제 #5
0
            internal void WriteCells(BinaryWriterEx bw, int i, Layout layout)
            {
                bw.FillInt64($"RowOffset{i}", bw.Position);
                for (int j = 0; j < layout.Count; j++)
                {
                    Cell         cell  = Cells[j];
                    Layout.Entry entry = layout[j];
                    CellType     type  = entry.Type;
                    object       value = cell.Value;

                    if (entry.Name != cell.Name || type != cell.Type)
                    {
                        throw new FormatException("Layout does not match cells.");
                    }

                    if (type == CellType.s8)
                    {
                        bw.WriteSByte((sbyte)value);
                    }
                    else if (type == CellType.u8 || type == CellType.x8)
                    {
                        bw.WriteByte((byte)value);
                    }
                    else if (type == CellType.s16)
                    {
                        bw.WriteInt16((short)value);
                    }
                    else if (type == CellType.u16 || type == CellType.x16)
                    {
                        bw.WriteUInt16((ushort)value);
                    }
                    else if (type == CellType.s32)
                    {
                        bw.WriteInt32((int)value);
                    }
                    else if (type == CellType.u32 || type == CellType.x32)
                    {
                        bw.WriteUInt32((uint)value);
                    }
                    else if (type == CellType.f32)
                    {
                        bw.WriteSingle((float)value);
                    }
                    else if (type == CellType.dummy8)
                    {
                        bw.WriteBytes((byte[])value);
                    }
                    else if (type == CellType.fixstr)
                    {
                        bw.WriteFixStr((string)value, entry.Size);
                    }
                    else if (type == CellType.fixstrW)
                    {
                        bw.WriteFixStrW((string)value, entry.Size);
                    }
                    else if (type == CellType.b8)
                    {
                        byte b = 0;
                        int  k;
                        for (k = 0; k < 8; k++)
                        {
                            if (j + k >= layout.Count || layout[j + k].Type != CellType.b8)
                            {
                                break;
                            }

                            if ((bool)Cells[j + k].Value)
                            {
                                b |= (byte)(1 << k);
                            }
                        }
                        j += k - 1;
                        bw.WriteByte(b);
                    }
                    else if (type == CellType.b32)
                    {
                        byte[] b = new byte[4];
                        int    k;
                        for (k = 0; k < 32; k++)
                        {
                            if (j + k >= layout.Count || layout[j + k].Type != CellType.b32)
                            {
                                break;
                            }

                            if ((bool)Cells[j + k].Value)
                            {
                                b[k / 8] |= (byte)(1 << (k % 8));
                            }
                        }
                        j += k - 1;
                        bw.WriteBytes(b);
                    }
                }
            }
예제 #6
0
            internal void WriteCells(BinaryWriterEx bw, byte format2D, int index)
            {
                if ((format2D & 0x7F) < 4)
                {
                    bw.FillUInt32($"RowOffset{index}", (uint)bw.Position);
                }
                else
                {
                    bw.FillInt64($"RowOffset{index}", bw.Position);
                }

                int bitOffset = -1;

                PARAMDEF.DefType bitType  = PARAMDEF.DefType.u8;
                uint             bitValue = 0;

                for (int i = 0; i < Cells.Count; i++)
                {
                    Cell             cell  = Cells[i];
                    object           value = cell.Value;
                    PARAMDEF.Field   field = cell.Def;
                    PARAMDEF.DefType type  = field.DisplayType;

                    if (type == PARAMDEF.DefType.s8)
                    {
                        bw.WriteSByte((sbyte)value);
                    }
                    else if (type == PARAMDEF.DefType.s16)
                    {
                        bw.WriteInt16((short)value);
                    }
                    else if (type == PARAMDEF.DefType.s32)
                    {
                        bw.WriteInt32((int)value);
                    }
                    else if (type == PARAMDEF.DefType.f32)
                    {
                        bw.WriteSingle((float)value);
                    }
                    else if (type == PARAMDEF.DefType.fixstr)
                    {
                        bw.WriteFixStr((string)value, field.ArrayLength);
                    }
                    else if (type == PARAMDEF.DefType.fixstrW)
                    {
                        bw.WriteFixStrW((string)value, field.ArrayLength * 2);
                    }
                    else if (ParamUtil.IsBitType(type))
                    {
                        if (field.BitSize == -1)
                        {
                            if (type == PARAMDEF.DefType.u8)
                            {
                                bw.WriteByte((byte)value);
                            }
                            else if (type == PARAMDEF.DefType.u16)
                            {
                                bw.WriteUInt16((ushort)value);
                            }
                            else if (type == PARAMDEF.DefType.u32)
                            {
                                bw.WriteUInt32((uint)value);
                            }
                            else if (type == PARAMDEF.DefType.dummy8)
                            {
                                bw.WriteBytes((byte[])value);
                            }
                        }
                        else
                        {
                            if (bitOffset == -1)
                            {
                                bitOffset = 0;
                                bitType   = type == PARAMDEF.DefType.dummy8 ? PARAMDEF.DefType.u8 : type;
                                bitValue  = 0;
                            }

                            uint shifted = 0;
                            if (bitType == PARAMDEF.DefType.u8)
                            {
                                shifted = (byte)value;
                            }
                            else if (bitType == PARAMDEF.DefType.u16)
                            {
                                shifted = (ushort)value;
                            }
                            else if (bitType == PARAMDEF.DefType.u32)
                            {
                                shifted = (uint)value;
                            }
                            // Shift left first to clear any out-of-range bits
                            shifted    = shifted << (32 - field.BitSize) >> (32 - field.BitSize - bitOffset);
                            bitValue  |= shifted;
                            bitOffset += field.BitSize;

                            bool write = false;
                            if (i == Cells.Count - 1)
                            {
                                write = true;
                            }
                            else
                            {
                                PARAMDEF.Field   nextField = Cells[i + 1].Def;
                                PARAMDEF.DefType nextType  = nextField.DisplayType;
                                int bitLimit = ParamUtil.GetBitLimit(bitType);
                                if (!ParamUtil.IsBitType(nextType) || nextField.BitSize == -1 || bitOffset + nextField.BitSize > bitLimit ||
                                    (nextType == PARAMDEF.DefType.dummy8 ? PARAMDEF.DefType.u8 : nextType) != bitType)
                                {
                                    write = true;
                                }
                            }

                            if (write)
                            {
                                bitOffset = -1;
                                if (bitType == PARAMDEF.DefType.u8)
                                {
                                    bw.WriteByte((byte)bitValue);
                                }
                                else if (bitType == PARAMDEF.DefType.u16)
                                {
                                    bw.WriteUInt16((ushort)bitValue);
                                }
                                else if (bitType == PARAMDEF.DefType.u32)
                                {
                                    bw.WriteUInt32(bitValue);
                                }
                            }
                        }
                    }
                    else
                    {
                        throw new NotImplementedException($"Unsupported field type: {type}");
                    }
                }
            }
예제 #7
0
        protected override void Write(BinaryWriterEx bw)
        {
            bw.BigEndian  = BigEndian;
            bw.VarintLong = Version == MQBVersion.DarkSouls2Scholar;

            bw.WriteASCII("MQB ");
            bw.WriteSByte((sbyte)(BigEndian ? -1 : 0));
            bw.WriteByte(0);
            bw.WriteSByte((sbyte)(Version == MQBVersion.DarkSouls2Scholar ? -1 : 0));
            bw.WriteByte(0);
            bw.WriteUInt32((uint)Version);
            switch (Version)
            {
            case MQBVersion.DarkSouls2: bw.WriteInt32(0x14); break;

            case MQBVersion.DarkSouls2Scholar: bw.WriteInt32(0x28); break;

            case MQBVersion.Bloodborne: bw.WriteInt32(0x20); break;

            case MQBVersion.DarkSouls3: bw.WriteInt32(0x24); break;

            default:
                throw new NotImplementedException($"Missing header size for version {Version}.");
            }

            bw.ReserveVarint("ResourcePathsOffset");
            if (Version == MQBVersion.DarkSouls2Scholar)
            {
                bw.WriteInt32(0);
                bw.WriteInt32(0);
                bw.WriteInt32(0);
                bw.WriteInt32(0);
            }
            else if (Version >= MQBVersion.Bloodborne)
            {
                bw.WriteInt32(1);
                bw.WriteInt32(0);
                bw.WriteInt32(0);
                if (Version >= MQBVersion.DarkSouls3)
                {
                    bw.WriteInt32(0);
                }
            }

            bw.WriteFixStrW(Name, 0x40, 0x00);
            bw.WriteSingle(Framerate);
            bw.WriteInt32(Resources.Count);
            bw.WriteInt32(Cuts.Count);
            bw.WriteInt32(0);
            bw.WriteInt32(0);
            bw.WriteInt32(0);
            bw.WriteInt32(0);
            bw.WriteInt32(0);

            var allCustomData          = new List <CustomData>();
            var customDataValueOffsets = new List <long>();

            for (int i = 0; i < Resources.Count; i++)
            {
                Resources[i].Write(bw, i, allCustomData, customDataValueOffsets);
            }

            var offsetsByDispos = new Dictionary <Disposition, long>();

            for (int i = 0; i < Cuts.Count; i++)
            {
                Cuts[i].Write(bw, Version, offsetsByDispos, i, allCustomData, customDataValueOffsets);
            }

            for (int i = 0; i < Cuts.Count; i++)
            {
                Cuts[i].WriteTimelines(bw, Version, i);
            }

            for (int i = 0; i < Cuts.Count; i++)
            {
                Cuts[i].WriteTimelineCustomData(bw, i, allCustomData, customDataValueOffsets);
            }

            for (int i = 0; i < Cuts.Count; i++)
            {
                Cuts[i].WriteDisposOffsets(bw, offsetsByDispos, i);
            }

            bw.FillVarint("ResourcePathsOffset", bw.Position);
            for (int i = 0; i < Resources.Count; i++)
            {
                bw.ReserveVarint($"ResourcePathOffset{i}");
            }

            bw.WriteUTF16(ResourceDirectory, true);
            for (int i = 0; i < Resources.Count; i++)
            {
                if (Resources[i].Path == null)
                {
                    bw.FillVarint($"ResourcePathOffset{i}", 0);
                }
                else
                {
                    bw.FillVarint($"ResourcePathOffset{i}", bw.Position);
                    bw.WriteUTF16(Resources[i].Path, true);
                }
            }

            // I know this is weird, but trust me.
            if (Version >= MQBVersion.Bloodborne)
            {
                bw.WriteInt16(0);
                bw.Pad(4);
            }

            for (int i = 0; i < allCustomData.Count; i++)
            {
                allCustomData[i].WriteSequences(bw, i, customDataValueOffsets[i]);
            }

            for (int i = 0; i < allCustomData.Count; i++)
            {
                allCustomData[i].WriteSequencePoints(bw, i);
            }
        }
예제 #8
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}");
                }
            }
예제 #9
0
            internal void Write(BinaryWriterEx bw, List <CustomData> allCustomData, List <long> customDataValueOffsets)
            {
                bw.WriteFixStrW(Name, 0x40, 0x00);
                bw.WriteUInt32((uint)Type);
                bw.WriteInt32(Type == DataType.Color ? 3 : 0);

                int length = -1;

                if (Type == DataType.String)
                {
                    length = SFEncoding.UTF16.GetByteCount((string)Value + '\0');
                    if (length % 0x10 != 0)
                    {
                        length += 0x10 - length % 0x10;
                    }
                }
                else if (Type == DataType.Custom)
                {
                    length = ((byte[])Value).Length;
                    if (length % 4 != 0)
                    {
                        throw new InvalidDataException($"Unexpected custom data custom length: {length}");
                    }
                }
                else if (Type == DataType.Color)
                {
                    length = 4;
                }

                long valueOffset = bw.Position;

                switch (Type)
                {
                case DataType.Bool: bw.WriteBoolean((bool)Value); break;

                case DataType.SByte: bw.WriteSByte((sbyte)Value); break;

                case DataType.Byte: bw.WriteByte((byte)Value); break;

                case DataType.Short: bw.WriteInt16((short)Value); break;

                case DataType.Int: bw.WriteInt32((int)Value); break;

                case DataType.UInt: bw.WriteUInt32((uint)Value); break;

                case DataType.Float: bw.WriteSingle((float)Value); break;

                case DataType.String:
                case DataType.Custom:
                case DataType.Color: bw.WriteInt32(length); break;

                default: throw new NotImplementedException($"Unimplemented custom data type: {Type}");
                }

                if (Type == DataType.Bool || Type == DataType.SByte || Type == DataType.Byte)
                {
                    bw.WriteByte(0);
                    bw.WriteInt16(0);
                }
                else if (Type == DataType.Short)
                {
                    bw.WriteInt16(0);
                }

                // This is probably wrong for the 64-bit format
                bw.WriteInt32(0);
                bw.ReserveInt32($"SequencesOffset[{allCustomData.Count}]");
                bw.WriteInt32(Sequences.Count);
                bw.WriteInt32(0);
                bw.WriteInt32(0);

                if (Type == DataType.String)
                {
                    bw.WriteFixStrW((string)Value, length, 0x00);
                }
                else if (Type == DataType.Custom)
                {
                    bw.WriteBytes((byte[])Value);
                }
                else if (Type == DataType.Color)
                {
                    var color = (Color)Value;
                    valueOffset = bw.Position;
                    bw.WriteByte(color.R);
                    bw.WriteByte(color.G);
                    bw.WriteByte(color.B);
                    bw.WriteByte(0);
                }

                allCustomData.Add(this);
                customDataValueOffsets.Add(valueOffset);
            }