mirror of
https://github.com/haven1433/HexManiacAdvance.git
synced 2026-10-02 05:06:35 -05:00
matched arrays extend together
This commit is contained in:
@@ -9,6 +9,7 @@ namespace HavenSoft.HexManiac.Core.Models {
|
||||
public interface IDataModel : IReadOnlyList<byte> {
|
||||
byte[] RawData { get; }
|
||||
new byte this[int index] { get; set; }
|
||||
IReadOnlyList<ArrayRun> Arrays { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If dataIndex is in the middle of a run, returns that run.
|
||||
@@ -58,6 +59,8 @@ namespace HavenSoft.HexManiac.Core.Models {
|
||||
|
||||
public BaseModel(byte[] data) => RawData = data;
|
||||
|
||||
public virtual IReadOnlyList<ArrayRun> Arrays { get; } = new List<ArrayRun>();
|
||||
|
||||
public byte this[int index] { get => RawData[index]; set => RawData[index] = value; }
|
||||
|
||||
byte IReadOnlyList<byte>.this[int index] => RawData[index];
|
||||
|
||||
@@ -27,6 +27,8 @@ namespace HavenSoft.HexManiac.Core.Models {
|
||||
|
||||
public virtual int EarliestAllowedAnchor => 0;
|
||||
|
||||
public override IReadOnlyList<ArrayRun> Arrays => runs.OfType<ArrayRun>().ToList();
|
||||
|
||||
#region Constructor
|
||||
|
||||
public PokemonModel(byte[] data, StoredMetadata metadata = null) : base(data) {
|
||||
|
||||
@@ -284,6 +284,8 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
|
||||
var nameWithQuotes = PCSString.Convert(owner, nameAddress, sourceArray.ElementContent[0].Length).Trim();
|
||||
if (nameWithQuotes.Contains(' ')) {
|
||||
names.Add(nameWithQuotes);
|
||||
} else if (nameWithQuotes.Length < 2) { // final name could just be a single closing quote and nothing else
|
||||
names.Add(nameWithQuotes);
|
||||
} else {
|
||||
var nameWithoutQuotes = nameWithQuotes.Substring(1, nameWithQuotes.Length - 2);
|
||||
names.Add(nameWithoutQuotes);
|
||||
@@ -330,15 +332,14 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
|
||||
Length = ElementLength * ElementCount;
|
||||
}
|
||||
|
||||
private ArrayRun(IDataModel data, string format, int start, int elementCount, IReadOnlyList<ArrayRunElementSegment> segments, IReadOnlyList<int> pointerSources, IReadOnlyList<IReadOnlyList<int>> pointerSourcesForInnerElements) : base(start, pointerSources) {
|
||||
private ArrayRun(IDataModel data, string format, string lengthFromAnchor, int start, int elementCount, IReadOnlyList<ArrayRunElementSegment> segments, IReadOnlyList<int> pointerSources, IReadOnlyList<IReadOnlyList<int>> pointerSourcesForInnerElements) : base(start, pointerSources) {
|
||||
owner = data;
|
||||
FormatString = format;
|
||||
ElementContent = segments;
|
||||
ElementLength = ElementContent.Sum(e => e.Length);
|
||||
ElementCount = elementCount;
|
||||
var closeArray = format.LastIndexOf(ArrayEnd.ToString());
|
||||
var length = format.Substring(closeArray + 1);
|
||||
LengthFromAnchor = length;
|
||||
LengthFromAnchor = lengthFromAnchor;
|
||||
Length = ElementLength * ElementCount;
|
||||
SupportsPointersToElements = pointerSourcesForInnerElements != null;
|
||||
PointerSourcesForInnerElements = pointerSourcesForInnerElements;
|
||||
@@ -371,11 +372,11 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
|
||||
if (string.IsNullOrEmpty(length)) {
|
||||
var bestAddress = StandardSearch(data, elementContent, elementLength, out int bestLength);
|
||||
if (bestAddress == Pointer.NULL) return false;
|
||||
self = new ArrayRun(data, originalFormat + bestLength, bestAddress, bestLength, elementContent, data.GetNextRun(bestAddress).PointerSources, null);
|
||||
self = new ArrayRun(data, originalFormat + bestLength, string.Empty, bestAddress, bestLength, elementContent, data.GetNextRun(bestAddress).PointerSources, null);
|
||||
} else {
|
||||
var bestAddress = KnownLengthSearch(data, elementContent, elementLength, length, out int bestLength, runFilter);
|
||||
if (bestAddress == Pointer.NULL) return false;
|
||||
self = new ArrayRun(data, originalFormat, bestAddress, bestLength, elementContent, data.GetNextRun(bestAddress).PointerSources, null);
|
||||
self = new ArrayRun(data, originalFormat, string.Empty, bestAddress, bestLength, elementContent, data.GetNextRun(bestAddress).PointerSources, null);
|
||||
}
|
||||
|
||||
if (allowPointersToEntries) self = self.AddSourcesPointingWithinArray(changeToken);
|
||||
@@ -504,7 +505,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
|
||||
var lastArrayCharacterIndex = FormatString.LastIndexOf(ArrayEnd);
|
||||
var newFormat = FormatString.Substring(0, lastArrayCharacterIndex + 1);
|
||||
if (newFormat != FormatString) newFormat += ElementCount + elementCount;
|
||||
return new ArrayRun(owner, newFormat, Start, ElementCount + elementCount, ElementContent, PointerSources, PointerSourcesForInnerElements);
|
||||
return new ArrayRun(owner, newFormat, LengthFromAnchor, Start, ElementCount + elementCount, ElementContent, PointerSources, PointerSourcesForInnerElements);
|
||||
}
|
||||
|
||||
public ArrayRun AddSourcePointingWithinArray(int source) {
|
||||
@@ -514,7 +515,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
|
||||
if (index == 0) throw new NotImplementedException();
|
||||
var newInnerPointerSources = PointerSourcesForInnerElements.ToList();
|
||||
newInnerPointerSources[index] = newInnerPointerSources[index].Concat(new[] { source }).ToList();
|
||||
return new ArrayRun(owner, FormatString, Start, ElementCount, ElementContent, PointerSources, newInnerPointerSources);
|
||||
return new ArrayRun(owner, FormatString, LengthFromAnchor, Start, ElementCount, ElementContent, PointerSources, newInnerPointerSources);
|
||||
}
|
||||
|
||||
public ArrayRun AddSourcesPointingWithinArray(ModelDelta changeToken) {
|
||||
@@ -536,7 +537,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
|
||||
}
|
||||
|
||||
var pointerSourcesForInnerElements = results.Cast<IReadOnlyList<int>>().ToList();
|
||||
return new ArrayRun(owner, FormatString, Start, ElementCount, ElementContent, PointerSources, pointerSourcesForInnerElements);
|
||||
return new ArrayRun(owner, FormatString, LengthFromAnchor, Start, ElementCount, ElementContent, PointerSources, pointerSourcesForInnerElements);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -575,7 +576,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
|
||||
}
|
||||
|
||||
public IFormattedRun Move(int newStart) {
|
||||
return new ArrayRun(owner, FormatString, newStart, ElementCount, ElementContent, PointerSources, PointerSourcesForInnerElements);
|
||||
return new ArrayRun(owner, FormatString, LengthFromAnchor, newStart, ElementCount, ElementContent, PointerSources, PointerSourcesForInnerElements);
|
||||
}
|
||||
|
||||
public override IFormattedRun RemoveSource(int source) {
|
||||
@@ -586,7 +587,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
|
||||
newInnerPointerSources.Add(list.Where(item => item != source).ToList());
|
||||
}
|
||||
|
||||
return new ArrayRun(owner, FormatString, Start, ElementCount, ElementContent, newPointerSources, newInnerPointerSources);
|
||||
return new ArrayRun(owner, FormatString, LengthFromAnchor, Start, ElementCount, ElementContent, newPointerSources, newInnerPointerSources);
|
||||
}
|
||||
|
||||
protected override IFormattedRun Clone(IReadOnlyList<int> newPointerSources) {
|
||||
@@ -598,7 +599,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
|
||||
for (int i = 1; i < PointerSourcesForInnerElements.Count; i++) newInnerPointerSources.Add(PointerSourcesForInnerElements[i]);
|
||||
}
|
||||
|
||||
return new ArrayRun(owner, FormatString, Start, ElementCount, ElementContent, newPointerSources, newInnerPointerSources);
|
||||
return new ArrayRun(owner, FormatString, LengthFromAnchor, Start, ElementCount, ElementContent, newPointerSources, newInnerPointerSources);
|
||||
}
|
||||
|
||||
private static List<ArrayRunElementSegment> ParseSegments(string segments) {
|
||||
|
||||
@@ -986,14 +986,48 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
|
||||
}
|
||||
|
||||
private void CompleteArrayExtension(ArrayRun arrayRun) {
|
||||
var newRun = (ArrayRun)Model.RelocateForExpansion(history.CurrentChange, arrayRun, arrayRun.Length + arrayRun.ElementLength);
|
||||
if (newRun != arrayRun) {
|
||||
var originalArray = arrayRun;
|
||||
var currentArrayName = Model.GetAnchorFromAddress(-1, arrayRun.Start);
|
||||
|
||||
int depth = 0;
|
||||
while (arrayRun.LengthFromAnchor != string.Empty) {
|
||||
depth++;
|
||||
if (depth == 10) {
|
||||
// We kept going up the chain of tables but didn't find a top table. Either the table length definitions are circular or very deep.
|
||||
OnError?.Invoke(this, "Could not extend table safely. Make sure you don't have a circular or deep dependency in your table lengths.");
|
||||
return;
|
||||
}
|
||||
var address = Model.GetAddressFromAnchor(new NoDataChangeDeltaModel(), -1, arrayRun.LengthFromAnchor);
|
||||
arrayRun = (ArrayRun)Model.GetNextRun(address);
|
||||
}
|
||||
|
||||
ExtendArrayAndChildren(arrayRun);
|
||||
|
||||
var newRun = (ArrayRun)Model.GetNextRun(Model.GetAddressFromAnchor(new NoDataChangeDeltaModel(), -1, currentArrayName));
|
||||
if (newRun.Start != originalArray.Start) {
|
||||
ScrollFromRunMove(arrayRun.Start + arrayRun.Length, arrayRun.Length, newRun);
|
||||
}
|
||||
Model.ObserveRunWritten(history.CurrentChange, arrayRun.Append(1));
|
||||
|
||||
RefreshBackingData();
|
||||
}
|
||||
|
||||
private void ExtendArrayAndChildren(ArrayRun array) {
|
||||
var newRun = (ArrayRun)Model.RelocateForExpansion(history.CurrentChange, array, array.Length + array.ElementLength);
|
||||
newRun = newRun.Append(1);
|
||||
Model.ObserveRunWritten(history.CurrentChange, newRun);
|
||||
|
||||
foreach(var child in GetDependantArrays(newRun)) {
|
||||
ExtendArrayAndChildren(child);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<ArrayRun> GetDependantArrays(ArrayRun parent) {
|
||||
var anchor = Model.GetAnchorFromAddress(-1, parent.Start);
|
||||
foreach (var array in Model.Arrays) {
|
||||
if (array.LengthFromAnchor == anchor) yield return array;
|
||||
}
|
||||
}
|
||||
|
||||
private void CompletePointerEdit(Point point) {
|
||||
var element = currentView[point.X, point.Y];
|
||||
var underEdit = (UnderEdit)element.Format;
|
||||
|
||||
@@ -411,9 +411,10 @@ namespace HavenSoft.HexManiac.Tests {
|
||||
Assert.Equal(0x100, model.GetNextRun(0).Length);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Feature not implement yet. Feature is now prioritized beneath array support for pointers.")]
|
||||
[Fact]
|
||||
public void ArrayExtendsIfBasedOnAnotherNameWhichIsExtended() {
|
||||
var buffer = new byte[0x200];
|
||||
for (int i = 0; i < buffer.Length; i++) buffer[i] = 0xFF;
|
||||
var model = new PokemonModel(buffer);
|
||||
var viewPort = new ViewPort("file.txt", model) { Width = 0x10, Height = 0x10 };
|
||||
var errors = new List<string>();
|
||||
@@ -427,12 +428,12 @@ namespace HavenSoft.HexManiac.Tests {
|
||||
// test 1: enbiggen derived should enbiggen sample
|
||||
viewPort.SelectionStart = new Point(8, 8);
|
||||
viewPort.Edit("+");
|
||||
Assert.Equal(8 * 8 + 8, model.GetNextRun(0).Length);
|
||||
Assert.Equal(8 * 9, model.GetNextRun(0).Length);
|
||||
|
||||
// test 2: enbiggen sample should enbiggen derived
|
||||
viewPort.SelectionStart = new Point(8, 4);
|
||||
viewPort.Edit("+");
|
||||
Assert.Equal(10, model.GetNextRun(0x80).Length);
|
||||
Assert.Equal(1 * 10, model.GetNextRun(0x80).Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
Reference in New Issue
Block a user