////////////////////////////////////////// /// GetExample() /// Returns an example of this class, used /// for validating json serialization. ////////////////////////////////////////// public static ModificationData GetExample() { ModificationData example = new ModificationData(); example.Target = "Strength"; example.ModType = ModificationTypes.Flat; example.PerkKeys = new List<string>() { "PerkA", "PerkB" }; example.Amount = 3; return example; }
protected static void BuildModificationData(ModificationData A, ModificationData B) { int N = A.HashedPieces.Length; int M = B.HashedPieces.Length; int MAX = M + N + 1; var forwardDiagonal = new int[MAX + 1]; var reverseDiagonal = new int[MAX + 1]; BuildModificationData(A, 0, N, B, 0, M, forwardDiagonal, reverseDiagonal); }
////////////////////////////////////////// /// GetExample() /// Returns an example of this class, used /// for validating json serialization. ////////////////////////////////////////// public static ModificationData GetExample() { ModificationData example = new ModificationData(); example.Target = "Strength"; example.ModType = ModificationTypes.Flat; example.PerkKeys = new List <string>() { "PerkA", "PerkB" }; example.Amount = 3; return(example); }
////////////////////////////////////////// /// GetModification() /// Returns the modification for the /// incoming key of this effect (as an /// integer). ////////////////////////////////////////// public int GetModification(string i_strKey) { // find the modification ModificationData data = GetModificationData(i_strKey); // if the data is not null, return it's modification if (data != null) { return((int)data.Amount); } else { return(0); } }
public void Will_return_empty_modifications_for_empty_strings() { var differ = new TestableDiffer(); var a = new ModificationData(""); var b = new ModificationData(""); a.HashedPieces = new int[0]; b.HashedPieces = new int[0]; a.Modifications = new bool[a.HashedPieces.Length]; b.Modifications = new bool[b.HashedPieces.Length]; differ.TestBuildModificationData(a, b); Assert.Empty(a.Modifications); Assert.Empty(b.Modifications); }
public void Will_return_correct_modifications_count_for_random_data(int[] aLines, int[] bLines, int editLength) { var differ = new TestableDiffer(); var a = new ModificationData(""); var b = new ModificationData(""); a.HashedPieces = aLines; b.HashedPieces = bLines; a.Modifications = new bool[aLines.Length]; b.Modifications = new bool[bLines.Length]; differ.TestBuildModificationData(a, b); int modCount = a.Modifications.Count(x => x == true) + b.Modifications.Count(x => x == true); Assert.Equal(editLength, modCount); }
public void Will_return_all_modifications_for_non_empty_vs_empty_string() { var differ = new TestableDiffer(); var a = new ModificationData("cat\nhat\npat\nmatt"); var b = new ModificationData(""); a.HashedPieces = new[] { 1, 2, 3, 4 }; b.HashedPieces = new int[] { }; a.Modifications = new bool[a.HashedPieces.Length]; b.Modifications = new bool[b.HashedPieces.Length]; differ.TestBuildModificationData(a, b); foreach (var mod in a.Modifications) { Assert.True(mod); } }
private static void BuildPieceHashes(IDictionary <string, int> pieceHash, ModificationData data, bool ignoreWhitespace, bool ignoreCase, Func <string, string[]> chunker) { string[] pieces; if (string.IsNullOrEmpty(data.RawData)) { pieces = new string[0]; } else { pieces = chunker(data.RawData); } data.Pieces = pieces; data.HashedPieces = new int[pieces.Length]; data.Modifications = new bool[pieces.Length]; for (int i = 0; i < pieces.Length; i++) { string piece = pieces[i]; // if (ignoreWhitespace) piece = piece.TrimEnd(new char [] {(char)1}).Trim(); // 2015/7/18 if (ignoreWhitespace) { piece = piece.Trim(); } if (ignoreCase) { piece = piece.ToUpperInvariant(); } if (pieceHash.ContainsKey(piece)) { data.HashedPieces[i] = pieceHash[piece]; } else { data.HashedPieces[i] = pieceHash.Count; pieceHash[piece] = pieceHash.Count; } } }
public void Will_return_correct_modifications_for_strings_with_two_differences() { var differ = new TestableDiffer(); var a = new ModificationData("cat\nfat\ntac"); var b = new ModificationData("cat\nmatt\ntac"); a.HashedPieces = new[] { 1, 2, 3 }; b.HashedPieces = new[] { 1, 4, 3 }; a.Modifications = new bool[a.HashedPieces.Length]; b.Modifications = new bool[b.HashedPieces.Length]; differ.TestBuildModificationData(a, b); Assert.False(a.Modifications[0]); Assert.True(a.Modifications[1]); Assert.False(a.Modifications[2]); Assert.False(b.Modifications[0]); Assert.True(b.Modifications[1]); Assert.False(b.Modifications[2]); }
public void Will_return_no_modifications_for_same_strings() { var differ = new TestableDiffer(); var a = new ModificationData("cat\nhat\npat\nmatt"); var b = new ModificationData("cat\nhat\npat\nmatt"); a.HashedPieces = new[] { 1, 2, 3, 4 }; b.HashedPieces = new[] { 1, 2, 3, 4 }; a.Modifications = new bool[a.HashedPieces.Length]; b.Modifications = new bool[b.HashedPieces.Length]; differ.TestBuildModificationData(a, b); foreach (var mod in a.Modifications) { Assert.False(mod); } foreach (var mod in b.Modifications) { Assert.False(mod); } }
public void Will_return_all_modifications_for_unique_strings() { var differ = new TestableDiffer(); var a = new ModificationData("cat\nhat\npat\nmatt"); var b = new ModificationData("door\nfloor\nbore\nmore"); a.HashedPieces = new[] { 1, 2, 3, 4 }; b.HashedPieces = new[] { 5, 6, 7, 8 }; a.Modifications = new bool[a.HashedPieces.Length]; b.Modifications = new bool[b.HashedPieces.Length]; differ.TestBuildModificationData(a, b); foreach (var mod in a.Modifications) { Assert.True(mod); } foreach (var mod in b.Modifications) { Assert.True(mod); } }
public void Will_return_correct_modifications_two_partially_similar_strings() { var differ = new TestableDiffer(); var a = new ModificationData("cat\nhat\npat\nmatt"); var b = new ModificationData("cat\nmatt\ntac"); a.HashedPieces = new[] { 1, 2, 3, 4 }; b.HashedPieces = new[] { 1, 4, 5 }; a.Modifications = new bool[a.HashedPieces.Length]; b.Modifications = new bool[b.HashedPieces.Length]; differ.TestBuildModificationData(a, b); Assert.False(a.Modifications[0]); Assert.True(a.Modifications[1]); Assert.True(a.Modifications[2]); Assert.False(a.Modifications[3]); Assert.False(b.Modifications[0]); Assert.False(b.Modifications[1]); Assert.True(b.Modifications[2]); }
private void UpdateStats(ModificationData modData) { if (!modData.changed) { return; } statsLock.EnterWriteLock(); try { currentStats.NumRomBytesModified++; currentStats.NumMarksModified += modData.mMarks ? 1 : 0; currentStats.NumDbModified += modData.mDb ? 1 : 0; currentStats.NumDpModified += modData.mDp ? 1 : 0; currentStats.NumXFlagsModified += modData.mX ? 1 : 0; currentStats.NumMFlagsModified += modData.mM ? 1 : 0; } finally { statsLock.ExitWriteLock(); } }
public bool ParseTextLine(string line, ModificationData modData) { // caution: very performance-sensitive function, please take care when making modifications // string.IndexOf() is super-slow too. // Input lines must follow this strict format and be this exact formatting and column indices. // 028cde rep #$30 A:0004 X:0000 Y:0004 S:1fdd D:0000 DB:02 nvmxdiZC V:133 H: 654 F:36 if (line.Length < 80) { return(false); } // performance: we could just parse the whitespace, but, // tracelogs have a huge amount of lines. so we parse the first line, // then save the offsets for all other lines in the same file. if (TextImportFormatCached.LastLineLength != line.Length) { TextImportFormatCached.RecomputeCachedIndicesBasedOn(line); } // TODO: add error treatment / validation here. modData.SnesAddress = (int)ByteUtil.ByteParseHex(line, 0, 6); modData.DirectPage = (int)ByteUtil.ByteParseHex(line, TextImportFormatCached.D, 4); modData.DataBank = (int)ByteUtil.ByteParseHex(line, TextImportFormatCached.Db, 2); // 'X' (if emulation mode) or 'B' (if native mode) = unchecked in bsnesplus debugger UI = (8bit) // 'x' or '.' = checked (16bit) modData.XFlagSet = line[TextImportFormatCached.Fx] == 'X' || line[TextImportFormatCached.Fx] == 'B'; // 'M' (if emulation mode) or '1' (if native mode) = unchecked in bsnesplus debugger UI = (8bit) // 'm' or '.' = checked (16bit) modData.MFlagSet = line[TextImportFormatCached.Fm] == 'M' || line[TextImportFormatCached.Fm] == '1'; // TODO: we could capture native vs emulation mode here and mark that. return(true); }
public DiffResult CreateCustomDiffs(string oldText, string newText, bool ignoreWhiteSpace, bool ignoreCase, Func <string, string[]> chunker) { if (oldText == null) { throw new ArgumentNullException("oldText"); } if (newText == null) { throw new ArgumentNullException("newText"); } if (chunker == null) { throw new ArgumentNullException("chunker"); } var pieceHash = new Dictionary <string, int>(); var lineDiffs = new List <DiffBlock>(); var modOld = new ModificationData(oldText); var modNew = new ModificationData(newText); BuildPieceHashes(pieceHash, modOld, ignoreWhiteSpace, ignoreCase, chunker); BuildPieceHashes(pieceHash, modNew, ignoreWhiteSpace, ignoreCase, chunker); BuildModificationData(modOld, modNew); int piecesALength = modOld.HashedPieces.Length; int piecesBLength = modNew.HashedPieces.Length; int posA = 0; int posB = 0; do { while (posA < piecesALength && posB < piecesBLength && !modOld.Modifications[posA] && !modNew.Modifications[posB]) { posA++; posB++; } int beginA = posA; int beginB = posB; for (; posA < piecesALength && modOld.Modifications[posA]; posA++) { ; } for (; posB < piecesBLength && modNew.Modifications[posB]; posB++) { ; } int deleteCount = posA - beginA; int insertCount = posB - beginB; if (deleteCount > 0 || insertCount > 0) { lineDiffs.Add(new DiffBlock(beginA, deleteCount, beginB, insertCount)); } } while (posA < piecesALength && posB < piecesBLength); return(new DiffResult(modOld.Pieces, modNew.Pieces, lineDiffs)); }
private static void BuildModificationData (ModificationData A, int startA, int endA, ModificationData B, int startB, int endB, int[] forwardDiagonal, int[] reverseDiagonal) { while (startA < endA && startB < endB && A.HashedPieces[startA].Equals(B.HashedPieces[startB])) { startA++; startB++; } while (startA < endA && startB < endB && A.HashedPieces[endA - 1].Equals(B.HashedPieces[endB - 1])) { endA--; endB--; } int aLength = endA - startA; int bLength = endB - startB; if (aLength > 0 && bLength > 0) { EditLengthResult res = CalculateEditLength(A.HashedPieces, startA, endA, B.HashedPieces, startB, endB, forwardDiagonal, reverseDiagonal); if (res.EditLength <= 0) { return; } if (res.LastEdit == Edit.DeleteRight && res.StartX - 1 > startA) { A.Modifications[--res.StartX] = true; } else if (res.LastEdit == Edit.InsertDown && res.StartY - 1 > startB) { B.Modifications[--res.StartY] = true; } else if (res.LastEdit == Edit.DeleteLeft && res.EndX < endA) { A.Modifications[res.EndX++] = true; } else if (res.LastEdit == Edit.InsertUp && res.EndY < endB) { B.Modifications[res.EndY++] = true; } BuildModificationData(A, startA, res.StartX, B, startB, res.StartY, forwardDiagonal, reverseDiagonal); BuildModificationData(A, res.EndX, endA, B, res.EndY, endB, forwardDiagonal, reverseDiagonal); } else if (aLength > 0) { for (int i = startA; i < endA; i++) { A.Modifications[i] = true; } } else if (bLength > 0) { for (int i = startB; i < endB; i++) { B.Modifications[i] = true; } } }
private void ApplyModificationIfNeeded(ModificationData modData) { var romByte = snesData.Data.RomBytes[modData.Pc]; modData.ApplyModificationIfNeeded(romByte); }
private void ApplyModification(ModificationData modData) { ApplyModificationIfNeeded(modData); UpdateStats(modData); }
private void UpdatePCAddress(ModificationData modData) { modData.Pc = ConvertSnesToPc(modData.SnesAddress); }
public void TestBuildModificationData(ModificationData A, ModificationData B) { BuildModificationData(A, B); }
private void ApplyModificationIfNeeded(ModificationData modData) { var romByte = data.RomByteSource?.Bytes[modData.Pc]; modData.ApplyModificationIfNeeded(romByte); }
private static void ParseBinary(byte[] bytes, bool abridgedFormat, out byte opcodeLen, ModificationData modData) { // file format info from the BSNES side: // https://github.com/binary1230/bsnes-plus/blob/e30dfc784f3c40c0db0a09124db4ec83189c575c/bsnes/snes/cpu/core/disassembler/disassembler.cpp#L224 // extremely performance-intensive function. be really careful when adding stuff if (abridgedFormat) { if (bytes.Length != 8) { throw new InvalidDataException("Non-abridged trace data length must be 8 bytes"); } } else { if (bytes.Length != 21) { throw new InvalidDataException("Non-abridged trace data length must be 21 bytes"); } } var currentIndex = 0; // ----------------------------- modData.SnesAddress = ByteUtil.ByteArrayToInt24(bytes, currentIndex); currentIndex += 3; opcodeLen = bytes[currentIndex++]; modData.DirectPage = ByteUtil.ByteArrayToInt16(bytes, currentIndex); currentIndex += 2; modData.DataBank = bytes[currentIndex++]; // the flags register var flags = bytes[currentIndex++]; // n = flags & 0x80; // v = flags & 0x40; // m = flags & 0x20; // d = flags & 0x08; // i = flags & 0x04; // z = flags & 0x02; // c = flags & 0x01; // we only care about X and M flags modData.XFlagSet = (flags & 0x10) != 0; modData.MFlagSet = (flags & 0x20) != 0; if (!abridgedFormat) { // skip opcodes. NOTE: must read all 5 bytes but only use up to 'opcode_len' bytes //var op = bytes[currentIndex++]; //var op0 = bytes[currentIndex++]; //var op1 = bytes[currentIndex++]; //var op2 = bytes[currentIndex++]; currentIndex += 4; // skip A register currentIndex += 2; // skip X register currentIndex += 2; // skip Y register currentIndex += 2; // skip S register currentIndex += 2; // skip, flag 'e' for emulation mode or not // skip E(emu) flag <-- NOTE: we might... want this someday. currentIndex += 1; } Debug.Assert(currentIndex == bytes.Length); }