public static byte[] BytesFrom(this IDataModel model, IFormattedRun run) { var data = new byte[run.Length]; Array.Copy(model.RawData, run.Start, data, 0, run.Length); return(data); }
public void RemoveRun(IFormattedRun run) { if (addedRuns.ContainsKey(run.Start)) { addedRuns.Remove(run.Start); } else if (!removedRuns.ContainsKey(run.Start)) { removedRuns[run.Start] = run; } }
public void RemoveRun(IFormattedRun run) { using (CaptureNonDataChange()) if (addedRuns.ContainsKey(run.Start)) { addedRuns.Remove(run.Start); } else if (!removedRuns.ContainsKey(run.Start)) { removedRuns[run.Start] = run; } }
public static bool ContainsOnlyPointerToSelf(this IFormattedRun run) { if (run.PointerSources == null) { return(false); } if (run.PointerSources.Count != 1) { return(false); } var source = run.PointerSources[0]; return(source >= run.Start && source < run.Start + run.Length); }
public override bool Matches(IFormattedRun run) { if (run is not TableStreamRun tableRun) { return(false); } if (!tableRun.AllowsZeroElements) { return(false); } if (tableRun.ElementContent.Count != 1) { return(false); } if (tableRun.ElementContent[0] is not ArrayRunPointerSegment pointerSegment) { return(false); } return(pointerSegment.InnerFormat.StartsWith("`uct4x") && pointerSegment.InnerFormat.EndsWith("`")); }
public override bool Matches(IFormattedRun run) { if (!(run is TilemapRun tilemapRun)) { return(false); } if (tilemapRun.Format.TileWidth != format.TileWidth) { return(false); } if (tilemapRun.Format.TileHeight != format.TileHeight) { return(false); } if (tilemapRun.Format.BitsPerPixel != format.BitsPerPixel) { return(false); } return(tilemapRun.Format.ExpectedUncompressedLength == format.ExpectedUncompressedLength); }
public override ErrorInfo TryParseData(IDataModel model, string name, int dataIndex, ref IFormattedRun run) { var error = SpriteRunContentStrategy.IsValid(format.BitsPerPixel); if (error.HasError) { return(error); } var newRun = new TilemapRun(model, dataIndex, format); run = newRun; return(ErrorInfo.NoError); }
public override ErrorInfo TryParseData(IDataModel model, string name, int dataIndex, ref IFormattedRun run) { run = new EggMoveRun(model, dataIndex); return(ErrorInfo.NoError); }
private static bool DataMatchesSegmentFormat(IDataModel owner, int start, ArrayRunElementSegment segment, FormatMatchFlags flags, IFormattedRun nextAnchor) { if (start + segment.Length > nextAnchor.Start && nextAnchor is ArrayRun) { return(false); // don't blap over existing arrays } switch (segment.Type) { case ElementContentType.PCS: int readLength = PCSString.ReadString(owner, start, true, segment.Length); if (readLength < 2) { return(false); } if (readLength > segment.Length) { return(false); } if (Enumerable.Range(start, segment.Length).All(i => owner[i] == 0xFF)) { return(false); } // if we end with a space, and the next one starts with a space, we probably have the data width wrong. // We might be the start of a different data segment that is no longer pointed to. (Example: Vega/pokenames) // only do this check if the current element seems useful var isBlank = Enumerable.Range(start, segment.Length).All(i => owner[i] == 0x00 || owner[i] == 0xFF); if (!isBlank && flags.HasFlag(FormatMatchFlags.IsSingleSegment) && start % 4 == 0 && owner[start + segment.Length - 1] == 0x00 && owner[start + segment.Length] == 0x00) { // if the next one starts on a 4-byte boundary, then we probably just skipped a few bytes between different data types, and _this_ section is still part of the _last_ run (example, Emerald Ability names) // if the next one doesn't start on a 4-byte boundary, then we probably have the length wrong var nextWordStart = (start + segment.Length + 3) / 4 * 4; if (Enumerable.Range(start + segment.Length, nextWordStart - start - segment.Length).Any(i => owner[i] != 0x00) || owner[nextWordStart] == 0x00) { return(false); } } // require that the overall thing still ends with 'FF' or '00' to avoid finding text of the wrong width. // the width check is less important if we have more complex data, so relax the condition (example: Clover) // the width check is less important if we're already known to be in a long run (example: Gaia moves) var lastByteInText = owner[start + segment.Length - 1]; var lastByteIsReasonablEnd = lastByteInText == 0x00 || lastByteInText == 0xFF; if (!flags.HasFlag(FormatMatchFlags.AllowJunkAfterText) && !lastByteIsReasonablEnd && flags.HasFlag(FormatMatchFlags.IsSingleSegment)) { return(false); } return(true); case ElementContentType.Integer: if (segment is ArrayRunEnumSegment enumSegment) { return(owner.ReadMultiByteValue(start, segment.Length) < enumSegment.GetOptions(owner).Count); } else { return(true); } case ElementContentType.Pointer: var destination = owner.ReadPointer(start); if (destination == Pointer.NULL) { return(true); } if (0 > destination || destination > owner.Count) { return(false); } if (segment is ArrayRunPointerSegment pointerSegment) { if (!pointerSegment.DestinationDataMatchesPointerFormat(owner, new NoDataChangeDeltaModel(), destination)) { return(false); } } return(true); case ElementContentType.BitArray: var bitArraySegment = (ArrayRunBitArraySegment)segment; var bits = bitArraySegment.GetOptions(owner).Count; bits %= 8; if (bits == 0) { return(true); } var finalByte = owner[start + bitArraySegment.Length - 1]; finalByte >>= bits; return(finalByte == 0); // all the unneeded bits should be set to zero default: throw new NotImplementedException(); } }
/// <summary> /// A pointer format in a table has changed. /// Replace the given run with a new run of the appropriate format. /// </summary> public abstract void UpdateNewRunFromPointerFormat(IDataModel model, ModelDelta token, string name, IReadOnlyList <ArrayRunElementSegment> sourceSegments, int parentIndex, ref IFormattedRun run);
public override void UpdateNewRunFromPointerFormat(IDataModel model, ModelDelta token, string name, ref IFormattedRun run) { var runAttempt = new TrainerPokemonTeamRun(model, run.Start, run.PointerSources); model.ClearFormat(token, run.Start, runAttempt.Length); run = runAttempt; }
public override ErrorInfo TryParseData(IDataModel model, string name, int dataIndex, ref IFormattedRun run) { if (int.TryParse(Format.Substring(5), out var length)) { run = new AsciiRun(model, dataIndex, length); } else { return(new ErrorInfo($"Ascii runs must include a length.")); } return(ErrorInfo.NoError); }
public override bool Matches(IFormattedRun run) => throw new NotImplementedException();
public override ErrorInfo TryParseData(IDataModel model, string name, int dataIndex, ref IFormattedRun run) { var newRun = new OverworldSpriteListRun(model, parentTemplate, Hint, 0, dataIndex, run.PointerSources); if (newRun.Length > 0) { run = newRun; return(ErrorInfo.NoError); } newRun = new OverworldSpriteListRun(model, parentTemplate2, Hint, 0, dataIndex, run.PointerSources); if (newRun.Length > 0) { run = newRun; return(ErrorInfo.NoError); } return(new ErrorInfo($"Could not at overworld sprite at {dataIndex}")); }
public override void UpdateNewRunFromPointerFormat(IDataModel model, ModelDelta token, string name, IReadOnlyList <ArrayRunElementSegment> sourceSegments, int parentIndex, ref IFormattedRun run) { var newRun = new TilemapRun(model, run.Start, format, run.PointerSources); model.ClearFormat(token, newRun.Start, newRun.Length); run = newRun; }
public static NoInfoRun Proxy(IFormattedRun run) => new NoInfoRun(run.Start, run.PointerSources);
public static object BuildContentForRun(IDataModel model, int source, int destination, IFormattedRun destinationRun, int preferredPaletteStart = -1, int preferredSpritePage = 0) { if (destination != destinationRun.Start) { return(null); } if (destinationRun is PCSRun pcs) { return(PCSString.Convert(model, pcs.Start, pcs.Length)); } else if (destinationRun is ISpriteRun sprite) { if (sprite is LzTilemapRun tilemap) { tilemap.FindMatchingTileset(model); } var paletteRuns = sprite.FindRelatedPalettes(model, source); var paletteRun = paletteRuns.FirstOrDefault(); if (preferredPaletteStart >= 0) { paletteRun = paletteRuns.FirstOrDefault(pRun => pRun.Start == preferredPaletteStart) ?? model.GetNextRun(preferredPaletteStart) as IPaletteRun; } var pixels = sprite.GetPixels(model, preferredSpritePage); if (pixels == null) { return(null); } var colors = paletteRun?.AllColors(model) ?? TileViewModel.CreateDefaultPalette((int)Math.Pow(2, sprite.SpriteFormat.BitsPerPixel)); var imageData = SpriteTool.Render(pixels, colors, paletteRun?.PaletteFormat.InitialBlankPages ?? 0, 0); return(new ReadonlyPixelViewModel(sprite.SpriteFormat, imageData)); } else if (destinationRun is IPaletteRun paletteRun) { var colors = paletteRun.GetPalette(model, 0); return(new ReadonlyPaletteCollection(colors)); } else if (destinationRun is IStreamRun streamRun) { using (ModelCacheScope.CreateScope(model)) { var lines = streamRun.SerializeRun().Split(Environment.NewLine); if (lines.Length > 20) { lines = lines.Take(20).ToArray(); } return(Environment.NewLine.Join(lines)); } } else if (destinationRun is ArrayRun arrayRun) { var stream = new StringBuilder(); arrayRun.AppendTo(model, stream, arrayRun.Start, arrayRun.ElementLength * Math.Min(20, arrayRun.ElementCount), false); return(stream.ToString()); } else { return(null); } }
public override void UpdateNewRunFromPointerFormat(IDataModel model, ModelDelta token, string name, ref IFormattedRun run) => throw new NotImplementedException();
public override ErrorInfo TryParseData(IDataModel model, string name, int dataIndex, ref IFormattedRun run) { var newRun = new TilemapRun(model, dataIndex, format); run = newRun; return(ErrorInfo.NoError); }
/// <summary> /// Attempt to parse the existing data into a run of the desired type. /// </summary> public abstract ErrorInfo TryParseData(IDataModel model, string name, int dataIndex, ref IFormattedRun run);
public override bool Matches(IFormattedRun run) => run is OverworldSpriteListRun;
public override bool Matches(IFormattedRun run) => run is PCSRun;
public override void UpdateNewRunFromPointerFormat(IDataModel model, ModelDelta token, string name, IReadOnlyList <ArrayRunElementSegment> sourceSegments, int parentIndex, ref IFormattedRun run) { run = new OverworldSpriteListRun(model, sourceSegments, Hint, parentIndex, run.Start, run.PointerSources); // backup: we may get asked to make a pointer format even when it's not an overworld sprite list. // if that happens, fall back to a NoInfoRun. if (run.Length == 0) { run = new NoInfoRun(run.Start, run.PointerSources); } }
public override void UpdateNewRunFromPointerFormat(IDataModel model, ModelDelta token, string name, ref IFormattedRun run) { var length = PCSString.ReadString(model, run.Start, true); if (length > 0) { var newRun = new PCSRun(model, run.Start, length, run.PointerSources); if (!newRun.Equals(run)) { model.ClearFormat(token, newRun.Start, newRun.Length); } run = newRun; } }
public override void UpdateNewRunFromPointerFormat(IDataModel model, ModelDelta token, string name, IReadOnlyList <ArrayRunElementSegment> sourceSegments, int parentIndex, ref IFormattedRun run) => throw new NotImplementedException();
public override ErrorInfo TryParseData(IDataModel model, string name, int dataIndex, ref IFormattedRun run) { var length = PCSString.ReadString(model, dataIndex, true); if (length < 0) { return(new ErrorInfo($"Format was specified as a string, but no string was recognized.")); } else if (PokemonModel.SpanContainsAnchor(model, dataIndex, length)) { return(new ErrorInfo($"Format was specified as a string, but a string would overlap the next anchor.")); } run = new PCSRun(model, dataIndex, length); return(ErrorInfo.NoError); }
public override bool Matches(IFormattedRun run) => run is TrainerPokemonTeamRun;
public override void UpdateNewRunFromPointerFormat(IDataModel model, ModelDelta token, string name, IReadOnlyList <ArrayRunElementSegment> sourceSegments, int parentIndex, ref IFormattedRun run) { var runAttempt = new TrainerPokemonTeamRun(model, run.Start, run.PointerSources); model.ClearFormat(token, run.Start, runAttempt.Length); run = runAttempt; }
public override ErrorInfo TryParseData(IDataModel model, string name, int dataIndex, ref IFormattedRun run) { run = new TrainerPokemonTeamRun(model, dataIndex, run.PointerSources); return(ErrorInfo.NoError); }
private static bool DataMatchesElementFormat(IDataModel owner, int start, IReadOnlyList <ArrayRunElementSegment> segments, FormatMatchFlags flags, IFormattedRun nextAnchor) { foreach (var segment in segments) { if (start + segment.Length > owner.Count) { return(false); } if (!DataMatchesSegmentFormat(owner, start, segment, flags, nextAnchor)) { return(false); } start += segment.Length; } return(true); }