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); } }
/// <summary> /// Calculates the size of cell data for each row. /// </summary> public int GetRowSize() { int size = 0; for (int i = 0; i < Fields.Count; i++) { Field field = Fields[i]; DefType type = field.DisplayType; if (ParamUtil.IsArrayType(type)) { size += ParamUtil.GetValueSize(type) * field.ArrayLength; } else { size += ParamUtil.GetValueSize(type); } if (ParamUtil.IsBitType(type) && field.BitSize != -1) { int bitOffset = field.BitSize; DefType bitType = type == DefType.dummy8 ? DefType.u8 : type; int bitLimit = ParamUtil.GetBitLimit(bitType); for (; i < Fields.Count - 1; i++) { Field nextField = Fields[i + 1]; DefType nextType = nextField.DisplayType; if (!ParamUtil.IsBitType(nextType) || nextField.BitSize == -1 || bitOffset + nextField.BitSize > bitLimit || (nextType == DefType.dummy8 ? DefType.u8 : nextType) != bitType) { break; } bitOffset += nextField.BitSize; } } } return(size); }
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); } } }
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}"); } }