private void ProcessNpcs( MajorRecordFrame majorFrame, long fileOffset) { if (majorFrame.TryLocateSubrecordFrame(RecordTypes.QNAM, out var qnamFrame, out var qnamLoc)) { // Standardize float rounding errors var r = IBinaryStreamExt.GetColorByte(qnamFrame.Content.Slice(0, 4).Float()); var g = IBinaryStreamExt.GetColorByte(qnamFrame.Content.Slice(4, 4).Float()); var b = IBinaryStreamExt.GetColorByte(qnamFrame.Content.Slice(8, 4).Float()); byte[] bytes = new byte[12]; using var writer = new MutagenWriter(new MemoryStream(bytes), majorFrame.Meta); writer.Write(r / 255f); writer.Write(g / 255f); writer.Write(b / 255f); this._Instructions.SetSubstitution(fileOffset + qnamLoc + qnamFrame.HeaderLength, bytes); } if (majorFrame.TryLocateSubrecordFrame(RecordTypes.NAM9, out var nam9Frame, out var nam9Loc)) { nam9Loc += nam9Frame.HeaderLength; var endPos = nam9Loc + nam9Frame.ContentLength; while (nam9Loc < endPos) { ProcessZeroFloat(majorFrame, fileOffset, ref nam9Loc); } } }
private void ProcessPlacedObject( MajorRecordFrame majorFrame, long fileOffset) { int amount = 0; if (majorFrame.TryLocateSubrecordFrame(RecordTypes.XLOC, out var xlocFrame, out var xlocLoc) && xlocFrame.ContentLength == 16) { ModifyLengthTracking(fileOffset, -4); var removeStart = fileOffset + xlocLoc + xlocFrame.HeaderLength + 12; this._instructions.SetSubstitution( loc: fileOffset + xlocLoc + 4, sub: new byte[] { 12, 0 }); this._instructions.SetRemove( section: new RangeInt64( removeStart, removeStart + 3)); amount -= 4; } if (majorFrame.TryLocateSubrecordFrame(RecordTypes.XSED, out var xsedFrame, out var xsedLoc)) { var len = xsedFrame.ContentLength; if (len == 4) { ModifyLengthTracking(fileOffset, -3); var removeStart = fileOffset + xsedLoc + xsedFrame.HeaderLength + 1; this._instructions.SetSubstitution( loc: fileOffset + xsedLoc + 4, sub: new byte[] { 1, 0 }); this._instructions.SetRemove( section: new RangeInt64( removeStart, removeStart + 2)); amount -= 3; } } if (majorFrame.TryLocateSubrecordPinFrame(RecordTypes.DATA, out var dataRec)) { ProcessZeroFloats(dataRec, fileOffset, 6); } if (majorFrame.TryLocateSubrecordPinFrame(RecordTypes.XTEL, out var xtelFrame)) { ProcessZeroFloats(xtelFrame, fileOffset, 6); } ProcessLengths( majorFrame, amount, fileOffset); }
private void ProcessCells( IMutagenReadStream stream, MajorRecordFrame majorFrame, long fileOffset) { var formKey = FormKey.Factory(stream.MetaData.MasterReferences !, majorFrame.FormID.Raw); CleanEmptyCellGroups( stream, formKey, fileOffset, numSubGroups: 2); // Process odd length changing flags var sizeChange = 0; if (majorFrame.TryLocateSubrecordFrame(RecordTypes.DATA, out var dataRec, out var dataIndex)) { if (dataRec.ContentLength == 1) { _Instructions.SetSubstitution( fileOffset + dataIndex + 4, 2); _Instructions.SetAddition( fileOffset + dataIndex + stream.MetaData.Constants.SubConstants.HeaderLength + 1, new byte[] { 0 }); sizeChange++; } } ProcessLengths( majorFrame, sizeChange, fileOffset); }
public void MajorMemoryFrameTryLocateSubrecordFrame() { var majorFrame = new MajorRecordFrame(GameConstants.Oblivion, _majorBytes); Assert.True(majorFrame.TryLocateSubrecordFrame(RecordTypes.DATA, out var subFrame, out var loc)); Assert.Equal(DataPos, loc); Assert.Equal(DataValue, subFrame.AsInt32()); }
private void ProcessFurniture( MajorRecordFrame majorFrame, long fileOffset) { // Find and store marker data var data = new Dictionary <int, ReadOnlyMemorySlice <byte> >(); var indices = new List <int>(); if (!majorFrame.TryLocateSubrecordFrame(RecordTypes.ENAM, out var enamFrame, out var initialPos)) { return; } var pos = initialPos - majorFrame.HeaderLength; while (pos < majorFrame.Content.Length) { var positions = UtilityTranslation.FindNextSubrecords( majorFrame.Content.Slice(pos), majorFrame.Meta, out var lenParsed, stopOnAlreadyEncounteredRecord: true, new RecordType[] { RecordTypes.ENAM, new RecordType("NAM0"), new RecordType("FNMK"), }); var enamPos = positions[0]; if (enamPos == null) { break; } enamFrame = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(pos + enamPos.Value)); var index = BinaryPrimitives.ReadInt32LittleEndian(enamFrame.Content); data.Add(index, majorFrame.Content.Slice(pos + enamPos.Value, lenParsed)); indices.Add(index); pos += lenParsed; } if (indices.SequenceEqual(indices.OrderBy(i => i))) { return; } byte[] reordered = new byte[data.Values.Select(l => l.Length).Sum()]; int transferPos = 0; foreach (var index in indices.OrderBy(i => i)) { var bytes = data[index]; bytes.Span.CopyTo(reordered.AsSpan().Slice(transferPos)); transferPos += bytes.Length; } this._Instructions.SetSubstitution(fileOffset + initialPos, reordered); }
private void ProcessLeveledItemDataFields( MajorRecordFrame majorFrame, long fileOffset) { if (!majorFrame.TryLocateSubrecordFrame(RecordTypes.DATA, out var dataFrame, out var dataIndex)) { return; } int amount = 0; var dataFlag = dataFrame.AsUInt8(); if (dataFlag == 1) { var lvld = majorFrame.LocateSubrecord(RecordTypes.LVLD, out var index); index += lvld.HeaderLength + 1; this._instructions.SetAddition( loc: index + fileOffset, addition: new byte[] { (byte)'L', (byte)'V', (byte)'L', (byte)'F', 0x1, 0x0, 0x2 }); amount += 7; } else { var existingLen = dataFrame.ContentLength; byte[] lenData = new byte[2]; using (var writer = new MutagenWriter(new MemoryStream(lenData), this.GameRelease)) { writer.Write((ushort)(existingLen - 7)); } this._instructions.SetSubstitution( loc: fileOffset + Plugins.Internals.Constants.HeaderLength, sub: lenData); } // Remove DATA var dataRange = new RangeInt64(dataIndex + fileOffset, dataIndex + fileOffset + 7 - 1); this._instructions.SetRemove(dataRange); amount -= (int)dataRange.Width; ProcessLengths( majorFrame, amount, fileOffset); }
private void ProcessWeathers( MajorRecordFrame majorFrame, long fileOffset) { if (majorFrame.TryLocateSubrecordFrame(RecordTypes.SNAM, out var _, out var initialIndex)) { foreach (var snam in majorFrame.FindEnumerateSubrecords(RecordTypes.SNAM)) { ProcessFormIDOverflow(snam, fileOffset); } } }
private void ProcessNavmeshes( MajorRecordFrame majorFrame, long fileOffset) { if (majorFrame.TryLocateSubrecordFrame(RecordTypes.NVNM, out var nvnmRec, out var nvnmIndex)) { nvnmIndex += nvnmRec.HeaderLength + 16; var count = majorFrame.HeaderAndContentData.Slice(nvnmIndex).Int32() * 3; nvnmIndex += 4; for (int i = 0; i < count; i++) { ProcessZeroFloat(majorFrame, fileOffset, ref nvnmIndex); } } }
private void ProcessGameSettings( MajorRecordFrame majorFrame, long fileOffset) { if (!majorFrame.TryLocateSubrecordFrame("EDID", out var edidFrame)) { return; } if ((char)edidFrame.Content[0] != 'f') { return; } if (!majorFrame.TryLocateSubrecordPinFrame(RecordTypes.DATA, out var dataRec)) { return; } ProcessZeroFloat(dataRec, fileOffset); }
private void ProcessPlaced( MajorRecordFrame majorFrame, long fileOffset) { var sizeChange = 0; if (majorFrame.TryLocateSubrecordPinFrame(RecordTypes.DATA, out var dataRec)) { ProcessZeroFloats(dataRec, fileOffset, 6); } if (majorFrame.TryLocateSubrecordPinFrame(RecordTypes.XTEL, out var xtelRec)) { var offset = 4; ProcessZeroFloats(xtelRec, fileOffset, ref offset, 6); } if (majorFrame.TryLocateSubrecordPinFrame(RecordTypes.XPRM, out var xprmRec)) { int offset = 0; ProcessZeroFloats(xprmRec, fileOffset, ref offset, 3); ProcessColorFloat(xprmRec, fileOffset, ref offset); ProcessZeroFloat(xprmRec, fileOffset, ref offset); } if (majorFrame.TryLocateSubrecordFrame(RecordTypes.XRMR, out var xrmrRec, out var xrmrIndex)) { if (xrmrRec.AsInt32() == 0) { _Instructions.SetRemove( RangeInt64.FactoryFromLength( fileOffset + xrmrIndex, 10)); sizeChange -= 10; } } ProcessLengths( majorFrame, sizeChange, fileOffset); }
private void ProcessDialogs( IMutagenReadStream stream, MajorRecordFrame majorFrame, long fileOffset) { var formKey = FormKey.Factory(stream.MetaData.MasterReferences !, majorFrame.FormID.Raw); CleanEmptyDialogGroups( stream, formKey, fileOffset); // Reset misnumbered counter if (majorFrame.TryLocateSubrecordFrame(RecordTypes.TIFC, out var tifcRec, out var tifcIndex)) { var count = tifcRec.AsUInt32(); uint actualCount = 0; stream.Position = fileOffset + majorFrame.TotalLength; if (stream.TryReadGroupFrame(out var groupFrame)) { int groupPos = 0; while (groupPos < groupFrame.Content.Length) { var majorMeta = stream.MetaData.Constants.MajorRecord(groupFrame.Content.Slice(groupPos)); actualCount++; groupPos += checked ((int)majorMeta.TotalLength); } } if (actualCount != count) { byte[] b = new byte[4]; BinaryPrimitives.WriteUInt32LittleEndian(b, actualCount); _Instructions.SetSubstitution( fileOffset + tifcIndex + stream.MetaData.Constants.SubConstants.HeaderLength, b); } } }
private void ProcessPackages( MajorRecordFrame majorFrame, long fileOffset) { // Reorder Idle subrecords // Reorder data values var xnamPos = UtilityTranslation.FindFirstSubrecord(majorFrame.Content, majorFrame.Meta, RecordTypes.XNAM); if (xnamPos == null) { throw new ArgumentException(); } if (!majorFrame.TryLocateSubrecordFrame(RecordTypes.PKCU, out var pkcuRec)) { throw new ArgumentException(); } var count = pkcuRec.Content.Int32(); if (count == 0) { return; } var anamPos = UtilityTranslation.FindFirstSubrecord(majorFrame.Content, majorFrame.Meta, RecordTypes.ANAM); RecordType pldt = new RecordType("PLDT"); RecordType ptda = new RecordType("PTDA"); RecordType pdto = new RecordType("PDTO"); RecordType tpic = new RecordType("TPIC"); RecordType unam = new RecordType("UNAM"); RecordType bnam = new RecordType("BNAM"); RecordType pnam = new RecordType("PNAM"); // Reorder data values to be in index ordering if (anamPos.HasValue && anamPos.Value < xnamPos.Value) { var startLoc = anamPos.Value; var dataValues = new List <(sbyte Index, ReadOnlyMemorySlice <byte> Data)>(); var curLoc = startLoc; while (anamPos.HasValue && anamPos.Value < xnamPos.Value) { var anamRecord = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(anamPos.Value)); var recs = UtilityTranslation.FindNextSubrecords( majorFrame.Content.Slice(anamPos.Value + anamRecord.TotalLength), majorFrame.Meta, out var _, RecordTypes.ANAM, RecordTypes.CNAM, pldt, ptda, pdto, tpic); int finalLoc; if (recs[0] == null) { finalLoc = recs.NotNull().Max(); } else if (recs[0] == 0) { dataValues.Add( (-1, majorFrame.Content.Slice(anamPos.Value, anamRecord.TotalLength))); curLoc = anamPos.Value + anamRecord.TotalLength; anamPos = anamPos.Value + anamRecord.TotalLength; continue; } else { finalLoc = recs .NotNull() .Where(i => i < recs[0] !.Value) .Max(); } var finalRec = majorFrame.Meta.Subrecord(majorFrame.Content.Slice(anamPos.Value + anamRecord.TotalLength + finalLoc)); var dataSlice = majorFrame.Content.Slice(anamPos.Value, anamRecord.TotalLength + finalLoc + finalRec.TotalLength); if (BinaryStringUtility.ProcessWholeToZString(anamRecord.Content) == "Bool" && recs[1] != null) { // Ensure bool value is 1 or 0 var cnam = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(anamPos.Value + anamRecord.TotalLength + recs[1].Value)); if (cnam.Content.Length != 1) { throw new ArgumentException(); } if (cnam.Content[0] > 1) { var bytes = dataSlice.ToArray(); int boolIndex = anamRecord.TotalLength + recs[1].Value + cnam.HeaderLength; bytes[boolIndex] = (byte)(bytes[boolIndex] > 0 ? 1 : 0); dataSlice = bytes; } } dataValues.Add((-1, dataSlice)); curLoc = anamPos.Value + anamRecord.TotalLength + finalLoc + finalRec.TotalLength; anamPos = anamPos.Value + anamRecord.TotalLength + recs[0]; } var unamLocs = UtilityTranslation.ParseRepeatingSubrecord( majorFrame.Content.Slice(curLoc), majorFrame.Meta, unam, out var _); if (unamLocs == null || unamLocs.Length != dataValues.Count || unamLocs.Length != count) { throw new ArgumentException(); } for (sbyte i = 0; i < unamLocs.Length; i++) { var unamRec = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(curLoc + unamLocs[i])); dataValues[i] = ( (sbyte)unamRec.Content[0], dataValues[i].Data); } var subLoc = startLoc; foreach (var item in dataValues.OrderBy(i => i.Index)) { _Instructions.SetSubstitution( fileOffset + majorFrame.HeaderLength + subLoc, item.Data.ToArray()); subLoc += item.Data.Length; } foreach (var item in dataValues.OrderBy(i => i.Index)) { byte[] bytes = new byte[] { 0x55, 0x4E, 0x41, 0x4D, 0x01, 0x00, 0x00 }; bytes[6] = (byte)item.Index; _Instructions.SetSubstitution( fileOffset + majorFrame.HeaderLength + subLoc, bytes.ToArray()); subLoc += bytes.Length; } } // Reorder inputs var unamPos = UtilityTranslation.FindFirstSubrecord(majorFrame.Content.Slice(xnamPos.Value), majorFrame.Meta, unam); if (!unamPos.HasValue) { return; } unamPos += xnamPos.Value; var writeLoc = fileOffset + majorFrame.HeaderLength + unamPos.Value; var inputValues = new List <(sbyte Index, ReadOnlyMemorySlice <byte> Data)>(); while (unamPos.HasValue) { var unamRecord = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(unamPos.Value)); var recs = UtilityTranslation.FindNextSubrecords( majorFrame.Content.Slice(unamPos.Value + unamRecord.TotalLength), majorFrame.Meta, out var _, unam, bnam, pnam); int finalLoc; if (recs[0] == null) { finalLoc = recs.NotNull().Max(); } else if (recs[0] == 0) { inputValues.Add( ((sbyte)unamRecord.Content[0], majorFrame.Content.Slice(unamPos.Value, unamRecord.TotalLength))); unamPos = unamPos.Value + unamRecord.TotalLength; continue; } else { finalLoc = recs .NotNull() .Where(i => i < recs[0] !.Value) .Max(); } var finalRec = majorFrame.Meta.Subrecord(majorFrame.Content.Slice(unamPos.Value + unamRecord.TotalLength + finalLoc)); inputValues.Add( ((sbyte)unamRecord.Content[0], majorFrame.Content.Slice(unamPos.Value, unamRecord.TotalLength + finalLoc + finalRec.TotalLength))); unamPos = unamPos.Value + unamRecord.TotalLength + recs[0]; } foreach (var item in inputValues.OrderBy(i => i.Index)) { _Instructions.SetSubstitution( writeLoc, item.Data.ToArray()); writeLoc += item.Data.Length; } }
private void ProcessQuests( MajorRecordFrame majorFrame, long fileOffset) { if (majorFrame.TryLocateSubrecordFrame(RecordTypes.ANAM, out var anamRec, out var anamIndex)) { var next = anamRec.AsUInt32(); var targets = new RecordType[] { RecordTypes.ALST, RecordTypes.ALLS }; var locs = UtilityTranslation.FindAllOfSubrecords( majorFrame.Content, majorFrame.Meta, targets.ToGetter(), navigateToContent: true); uint actualNext = 0; if (locs.Length > 0) { actualNext = locs .Select(l => { return(BinaryPrimitives.ReadUInt32LittleEndian(majorFrame.Content.Slice(l))); }) .Max(); actualNext++; } if (actualNext != next) { byte[] sub = new byte[4]; BinaryPrimitives.WriteUInt32LittleEndian(sub, actualNext); _Instructions.SetSubstitution( fileOffset + anamIndex + anamRec.HeaderLength, sub); } } var sizeChange = FixMissingCounters( majorFrame, fileOffset, new RecordType("COCT"), new RecordType("CNTO")); ProcessLengths( majorFrame, sizeChange, fileOffset); FixVMADFormIDs( majorFrame, fileOffset, out var vmadPos, out var objectFormat, out var processedLen); if (vmadPos != null) { var vmadFrame = Meta.SubrecordFrame(majorFrame.Content.Slice(vmadPos.Value)); var stream = new MutagenMemoryReadStream(vmadFrame.Content, Bundle) { Position = processedLen - vmadFrame.HeaderLength }; if (stream.Complete) { return; } // skip unknown stream.Position += 1; var fragCount = stream.ReadUInt16(); // skip name var len = stream.ReadUInt16(); stream.Position += len; for (int i = 0; i < fragCount; i++) { stream.Position += 9; // skip name len = stream.ReadUInt16(); stream.Position += len; // skip name len = stream.ReadUInt16(); stream.Position += len; } var aliasCount = stream.ReadUInt16(); for (int i = 0; i < aliasCount; i++) { FixObjectPropertyIDs(stream, fileOffset, objectFormat); // skip version stream.Position += 2; objectFormat = stream.ReadUInt16(); var numScripts = stream.ReadUInt16(); for (int j = 0; j < numScripts; j++) { FixVMADScriptIDs(stream, fileOffset, objectFormat); } } } }
private void ProcessRegions( IMutagenReadStream stream, MajorRecordFrame majorFrame, long fileOffset) { if (!majorFrame.TryLocateSubrecordFrame(RecordTypes.RDAT, out var rdatFrame, out var rdatIndex)) { return; } int amount = 0; SortedList <uint, RangeInt64> rdats = new SortedList <uint, RangeInt64>(); bool foundNext = true; while (foundNext) { foundNext = majorFrame.TryLocateSubrecordFrame(RecordTypes.RDAT, offset: rdatIndex + rdatFrame.TotalLength, out var nextRdatFrame, out var nextRdatIndex); var index = rdatFrame.Content.UInt32(); rdats[index] = new RangeInt64( rdatIndex + fileOffset, foundNext ? nextRdatIndex - 1 + fileOffset : fileOffset + majorFrame.TotalLength - 1); rdatFrame = nextRdatFrame; rdatIndex = nextRdatIndex; } foreach (var item in rdats.Reverse()) { if (item.Key == (int)RegionData.RegionDataType.Icon) { continue; } this._instructions.SetMove( loc: fileOffset + majorFrame.TotalLength, section: item.Value); } if (rdats.ContainsKey((int)RegionData.RegionDataType.Icon)) { // Need to create icon record if (!majorFrame.TryLocateSubrecordFrame("EDID", out var edidFrame, out var edidLoc)) { throw new ArgumentException(); } var locToPlace = fileOffset + edidLoc + edidFrame.TotalLength; // Get icon string var iconLoc = rdats[(int)RegionData.RegionDataType.Icon]; stream.Position = iconLoc.Min + 20; var iconStr = BinaryStringUtility.ToZString(stream.ReadMemory((int)(iconLoc.Max - stream.Position)), MutagenEncodingProvider._1252); // Get icon bytes MemoryStream memStream = new MemoryStream(); using (var writer = new MutagenWriter(memStream, this.GameRelease)) { using (HeaderExport.Header( writer, new RecordType("ICON"), ObjectType.Subrecord)) { StringBinaryTranslation.Instance.Write(writer, iconStr, StringBinaryType.NullTerminate); } } var arr = memStream.ToArray(); this._instructions.SetAddition( loc: locToPlace, addition: arr); this._instructions.SetRemove( section: iconLoc); amount += arr.Length; amount -= (int)iconLoc.Width; } ProcessLengths( majorFrame, amount, fileOffset); }