示例#1
0
            public static void Serialize(PARAMDEF def, XmlWriter xw, int xmlVersion)
            {
                if (xmlVersion < 0 || xmlVersion > CURRENT_XML_VERSION)
                {
                    throw new InvalidOperationException($"XML version {xmlVersion} not recognized.");
                }

                xw.WriteStartDocument();
                xw.WriteStartElement("PARAMDEF");
                xw.WriteAttributeString("XmlVersion", xmlVersion.ToString());
                xw.WriteElementString("ParamType", def.ParamType);
                xw.WriteElementString(xmlVersion == 0 ? "Unk06" : "DataVersion", def.DataVersion.ToString());
                xw.WriteElementString("BigEndian", def.BigEndian.ToString());
                xw.WriteElementString("Unicode", def.Unicode.ToString());
                xw.WriteElementString(xmlVersion == 0 ? "Version" : "FormatVersion", def.FormatVersion.ToString());

                xw.WriteStartElement("Fields");
                foreach (Field field in def.Fields)
                {
                    xw.WriteStartElement("Field");
                    SerializeField(field, xw);
                    xw.WriteEndElement();
                }
                xw.WriteEndElement();

                xw.WriteEndElement();
            }
示例#2
0
            internal void WriteDescription(BinaryWriterEx bw, PARAMDEF def, int index)
            {
                long descriptionOffset = 0;

                if (Description != null)
                {
                    descriptionOffset = bw.Position;
                    if (def.Unicode)
                    {
                        bw.WriteUTF16(Description, true);
                    }
                    else
                    {
                        bw.WriteShiftJIS(Description, true);
                    }
                }

                if (def.Version >= 201)
                {
                    bw.FillInt64($"DescriptionOffset{index}", descriptionOffset);
                }
                else
                {
                    bw.FillInt32($"DescriptionOffset{index}", (int)descriptionOffset);
                }
            }
示例#3
0
            internal Field(BinaryReaderEx br, PARAMDEF def)
            {
                if (def.Unicode)
                {
                    DisplayName = br.ReadFixStrW(0x40);
                }
                else
                {
                    DisplayName = br.ReadFixStr(0x40);
                }

                DisplayType   = (DefType)Enum.Parse(typeof(DefType), br.ReadFixStr(8));
                DisplayFormat = br.ReadFixStr(8);
                Default       = br.ReadSingle();
                Minimum       = br.ReadSingle();
                Maximum       = br.ReadSingle();
                Increment     = br.ReadSingle();
                EditFlags     = (EditFlags)br.ReadInt32();
                ByteCount     = br.ReadInt32();

                long descriptionOffset;

                if (def.Version >= 201)
                {
                    descriptionOffset = br.ReadInt64();
                }
                else
                {
                    descriptionOffset = br.ReadInt32();
                }

                InternalType = br.ReadFixStr(0x20);

                if (def.Version >= 102)
                {
                    InternalName = br.ReadFixStr(0x20);
                }

                if (def.Version >= 104)
                {
                    SortID = br.ReadInt32();
                }

                if (def.Version >= 201)
                {
                    br.AssertPattern(0x1C, 0x00);
                }

                if (descriptionOffset != 0)
                {
                    if (def.Unicode)
                    {
                        Description = br.GetUTF16(descriptionOffset);
                    }
                    else
                    {
                        Description = br.GetShiftJIS(descriptionOffset);
                    }
                }
            }
示例#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(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);
                }
            }
示例#5
0
 /// <summary>
 /// Interprets row data according to the given paramdef and stores it for later writing.
 /// </summary>
 public void ApplyParamdef(PARAMDEF paramdef)
 {
     AppliedParamdef = paramdef;
     foreach (Row row in Rows)
     {
         row.ReadCells(RowReader, AppliedParamdef);
     }
 }
示例#6
0
 /// <summary>
 /// Applies a paramdef only if its param type, data version, and row size match this param's. Returns true if applied.
 /// </summary>
 public bool ApplyParamdefCarefully(PARAMDEF paramdef)
 {
     if (ParamType == paramdef.ParamType && ParamdefDataVersion == paramdef.DataVersion &&
         (DetectedSize == -1 || DetectedSize == paramdef.GetRowSize()))
     {
         ApplyParamdef(paramdef);
         return(true);
     }
     return(false);
 }
示例#7
0
            /// <summary>
            /// Creates a new row based on the given paramdef with default values.
            /// </summary>
            public Row(long id, string name, PARAMDEF paramdef)
            {
                ID   = id;
                Name = name;

                var cells = new Cell[paramdef.Fields.Count];

                for (int i = 0; i < paramdef.Fields.Count; i++)
                {
                    PARAMDEF.Field field = paramdef.Fields[i];
                    object         value = ParamUtil.CastDefaultValue(field);
                    cells[i] = new Cell(field, value);
                }
                Cells = cells;
            }
示例#8
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);
                }
            }
示例#9
0
            public static PARAMDEF Deserialize(XmlDocument xml)
            {
                var     def  = new PARAMDEF();
                XmlNode root = xml.SelectSingleNode("PARAMDEF");

                // In the interest of maximum compatibility, we will no longer check the XML version;
                // just try everything and hope it works.

                def.ParamType     = root.SelectSingleNode("ParamType").InnerText;
                def.DataVersion   = root.ReadInt16IfExist("DataVersion") ?? root.ReadInt16("Unk06");
                def.BigEndian     = root.ReadBoolean("BigEndian");
                def.Unicode       = root.ReadBoolean("Unicode");
                def.FormatVersion = root.ReadInt16IfExist("FormatVersion") ?? root.ReadInt16("Version");

                def.Fields = new List <Field>();
                foreach (XmlNode node in root.SelectNodes("Fields/Field"))
                {
                    def.Fields.Add(DeserializeField(node));
                }

                return(def);
            }
示例#10
0
            internal void ReadCells(BinaryReaderEx br, PARAMDEF paramdef)
            {
                // In case someone decides to add new rows before applying the paramdef (please don't do that)
                if (DataOffset == 0)
                {
                    return;
                }

                Def = paramdef;

                br.Position = DataOffset;
                var cells = new Cell[paramdef.Fields.Count];

                int bitOffset = -1;

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

                for (int i = 0; i < paramdef.Fields.Count; i++)
                {
                    PARAMDEF.Field   field = paramdef.Fields[i];
                    object           value = null;
                    PARAMDEF.DefType type  = field.DisplayType;

                    if (type == PARAMDEF.DefType.s8)
                    {
                        value = br.ReadSByte();
                    }
                    else if (type == PARAMDEF.DefType.s16)
                    {
                        value = br.ReadInt16();
                    }
                    else if (type == PARAMDEF.DefType.s32)
                    {
                        value = br.ReadInt32();
                    }
                    else if (type == PARAMDEF.DefType.f32)
                    {
                        value = br.ReadSingle();
                    }
                    else if (type == PARAMDEF.DefType.fixstr)
                    {
                        value = br.ReadFixStr(field.ArrayLength);
                    }
                    else if (type == PARAMDEF.DefType.fixstrW)
                    {
                        value = br.ReadFixStrW(field.ArrayLength * 2);
                    }
                    else if (ParamUtil.IsBitType(type))
                    {
                        if (field.BitSize == -1)
                        {
                            if (type == PARAMDEF.DefType.u8)
                            {
                                value = br.ReadByte();
                            }
                            else if (type == PARAMDEF.DefType.u16)
                            {
                                value = br.ReadUInt16();
                            }
                            else if (type == PARAMDEF.DefType.u32)
                            {
                                value = br.ReadUInt32();
                            }
                            else if (type == PARAMDEF.DefType.dummy8)
                            {
                                value = br.ReadBytes(field.ArrayLength);
                            }
                        }
                    }
                    else
                    {
                        throw new NotImplementedException($"Unsupported field type: {type}");
                    }

                    if (value != null)
                    {
                        bitOffset = -1;
                    }
                    else
                    {
                        PARAMDEF.DefType newBitType = type == PARAMDEF.DefType.dummy8 ? PARAMDEF.DefType.u8 : type;
                        int bitLimit = ParamUtil.GetBitLimit(newBitType);

                        if (field.BitSize == 0)
                        {
                            throw new NotImplementedException($"Bit size 0 is not supported.");
                        }
                        if (field.BitSize > bitLimit)
                        {
                            throw new InvalidDataException($"Bit size {field.BitSize} is too large to fit in type {newBitType}.");
                        }

                        if (bitOffset == -1 || newBitType != bitType || bitOffset + field.BitSize > bitLimit)
                        {
                            bitOffset = 0;
                            bitType   = newBitType;
                            if (bitType == PARAMDEF.DefType.u8)
                            {
                                bitValue = br.ReadByte();
                            }
                            else if (bitType == PARAMDEF.DefType.u16)
                            {
                                bitValue = br.ReadUInt16();
                            }
                            else if (bitType == PARAMDEF.DefType.u32)
                            {
                                bitValue = br.ReadUInt32();
                            }
                        }

                        uint shifted = bitValue << (32 - field.BitSize - bitOffset) >> (32 - field.BitSize);
                        bitOffset += field.BitSize;
                        if (bitType == PARAMDEF.DefType.u8)
                        {
                            value = (byte)shifted;
                        }
                        else if (bitType == PARAMDEF.DefType.u16)
                        {
                            value = (ushort)shifted;
                        }
                        else if (bitType == PARAMDEF.DefType.u32)
                        {
                            value = shifted;
                        }
                    }

                    cells[i] = new Cell(field, value);
                }
                Cells = cells;
            }
示例#11
0
            /// <summary>
            /// Converts the layout to a paramdef with the given type, and all child enums to paramtdfs.
            /// </summary>
            public PARAMDEF ToParamdef(string paramType, out List <PARAMTDF> paramtdfs)
            {
                paramtdfs = new List <PARAMTDF>(Enums.Count);
                foreach (string enumName in Enums.Keys)
                {
                    paramtdfs.Add(Enums[enumName].ToParamtdf(enumName));
                }

                var def = new PARAMDEF {
                    ParamType = paramType, Unicode = true, FormatVersion = 201
                };

                foreach (Entry entry in this)
                {
                    PARAMDEF.DefType fieldType;
                    switch (entry.Type)
                    {
                    case CellType.dummy8: fieldType = PARAMDEF.DefType.dummy8; break;

                    case CellType.b8:
                    case CellType.u8:
                    case CellType.x8: fieldType = PARAMDEF.DefType.u8; break;

                    case CellType.s8: fieldType = PARAMDEF.DefType.s8; break;

                    case CellType.b16:
                    case CellType.u16:
                    case CellType.x16: fieldType = PARAMDEF.DefType.u16; break;

                    case CellType.s16: fieldType = PARAMDEF.DefType.s16; break;

                    case CellType.b32:
                    case CellType.u32:
                    case CellType.x32: fieldType = PARAMDEF.DefType.u32; break;

                    case CellType.s32: fieldType = PARAMDEF.DefType.s32; break;

                    case CellType.f32: fieldType = PARAMDEF.DefType.f32; break;

                    case CellType.fixstr: fieldType = PARAMDEF.DefType.fixstr; break;

                    case CellType.fixstrW: fieldType = PARAMDEF.DefType.fixstrW; break;

                    default:
                        throw new NotImplementedException($"DefType not specified for CellType {entry.Type}.");
                    }

                    var field = new PARAMDEF.Field(fieldType, entry.Name);
                    field.Description = entry.Description;
                    if (entry.Enum != null)
                    {
                        field.InternalType = entry.Enum;
                    }

                    if (entry.Type == CellType.s8)
                    {
                        field.Default = (sbyte)entry.Default;
                    }
                    else if (entry.Type == CellType.u8 || entry.Type == CellType.x8)
                    {
                        field.Default = (byte)entry.Default;
                    }
                    else if (entry.Type == CellType.s16)
                    {
                        field.Default = (short)entry.Default;
                    }
                    else if (entry.Type == CellType.u16 || entry.Type == CellType.x16)
                    {
                        field.Default = (ushort)entry.Default;
                    }
                    else if (entry.Type == CellType.s32)
                    {
                        field.Default = (int)entry.Default;
                    }
                    else if (entry.Type == CellType.u32 || entry.Type == CellType.x32)
                    {
                        field.Default = (uint)entry.Default;
                    }
                    else if (entry.Type == CellType.dummy8 || entry.Type == CellType.fixstr)
                    {
                        field.ArrayLength = entry.Size;
                    }
                    else if (entry.Type == CellType.fixstrW)
                    {
                        field.ArrayLength = entry.Size / 2;
                    }
                    else if (entry.Type == CellType.b8 || entry.Type == CellType.b16 || entry.Type == CellType.b32)
                    {
                        field.Default = (bool)entry.Default ? 1 : 0;
                        field.BitSize = 1;
                    }

                    def.Fields.Add(field);
                }
                return(def);
            }
示例#12
0
            internal Field(BinaryReaderEx br, PARAMDEF def)
            {
                Parent = def;
                if (def.Unicode)
                {
                    DisplayName = br.ReadFixStrW(0x40);
                }
                else
                {
                    DisplayName = br.ReadFixStr(0x40);
                }

                DisplayType   = (DefType)Enum.Parse(typeof(DefType), br.ReadFixStr(8));
                DisplayFormat = br.ReadFixStr(8);
                Default       = br.ReadSingle();
                Minimum       = br.ReadSingle();
                Maximum       = br.ReadSingle();
                Increment     = br.ReadSingle();
                EditFlags     = (EditFlags)br.ReadInt32();

                int byteCount = br.ReadInt32();

                if (!ParamUtil.IsArrayType(DisplayType) && byteCount != ParamUtil.GetValueSize(DisplayType) ||
                    ParamUtil.IsArrayType(DisplayType) && byteCount % ParamUtil.GetValueSize(DisplayType) != 0)
                {
                    throw new InvalidDataException($"Unexpected byte count {byteCount} for type {DisplayType}.");
                }
                ArrayLength = byteCount / ParamUtil.GetValueSize(DisplayType);

                long descriptionOffset;

                if (def.Version >= 201)
                {
                    descriptionOffset = br.ReadInt64();
                }
                else
                {
                    descriptionOffset = br.ReadInt32();
                }

                InternalType = br.ReadFixStr(0x20);

                BitSize = -1;
                if (def.Version >= 102)
                {
                    // A few fields in DS1 FaceGenParam have a trailing space in the name
                    InternalName = br.ReadFixStr(0x20).Trim();

                    Match match = bitSizeRx.Match(InternalName);
                    if (match.Success)
                    {
                        InternalName = match.Groups["name"].Value;
                        BitSize      = int.Parse(match.Groups["size"].Value);
                    }

                    if (ParamUtil.IsArrayType(DisplayType))
                    {
                        match = arrayLengthRx.Match(InternalName);
                        int length = match.Success ? int.Parse(match.Groups["length"].Value) : 1;
                        if (length != ArrayLength)
                        {
                            throw new InvalidDataException($"Mismatched array length in {InternalName} with byte count {byteCount}.");
                        }
                        if (match.Success)
                        {
                            InternalName = match.Groups["name"].Value;
                        }
                    }
                }

                if (def.Version >= 104)
                {
                    SortID = br.ReadInt32();
                }

                if (def.Version >= 201)
                {
                    br.AssertPattern(0x1C, 0x00);
                }

                if (descriptionOffset != 0)
                {
                    if (def.Unicode)
                    {
                        Description = br.GetUTF16(descriptionOffset);
                    }
                    else
                    {
                        Description = br.GetShiftJIS(descriptionOffset);
                    }
                }
            }
示例#13
0
            internal void WriteStrings(BinaryWriterEx bw, PARAMDEF def, int index, Dictionary <string, long> sharedStringOffsets)
            {
                if (def.FormatVersion >= 202)
                {
                    bw.FillInt64($"DisplayNameOffset{index}", bw.Position);
                    bw.WriteUTF16(DisplayName, true);
                }

                long descriptionOffset = 0;

                if (Description != null)
                {
                    descriptionOffset = bw.Position;
                    if (def.Unicode)
                    {
                        bw.WriteUTF16(Description, true);
                    }
                    else
                    {
                        bw.WriteShiftJIS(Description, true);
                    }
                }

                if (def.FormatVersion >= 200)
                {
                    bw.FillInt64($"DescriptionOffset{index}", descriptionOffset);
                }
                else
                {
                    bw.FillInt32($"DescriptionOffset{index}", (int)descriptionOffset);
                }

                if (def.FormatVersion >= 202)
                {
                    bw.FillInt64($"InternalTypeOffset{index}", bw.Position);
                    bw.WriteASCII(InternalType, true);

                    bw.FillInt64($"InternalNameOffset{index}", bw.Position);
                    bw.WriteASCII(MakeInternalName(), true);
                }

                if (def.FormatVersion >= 200)
                {
                    long writeSharedStringMaybe(string str, bool unicode)
                    {
                        if (str == null)
                        {
                            return(0);
                        }

                        if (!sharedStringOffsets.ContainsKey(str))
                        {
                            sharedStringOffsets[str] = bw.Position;
                            if (unicode)
                            {
                                bw.WriteUTF16(str, true);
                            }
                            else
                            {
                                bw.WriteASCII(str, true);
                            }
                        }
                        return(sharedStringOffsets[str]);
                    }

                    bw.FillInt64($"UnkB8Offset{index}", writeSharedStringMaybe(UnkB8, false));
                    bw.FillInt64($"UnkC0Offset{index}", writeSharedStringMaybe(UnkC0, false));
                    bw.FillInt64($"UnkC8Offset{index}", writeSharedStringMaybe(UnkC8, true));
                }
            }
示例#14
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}");
                }
            }