Add Free Space selector

Reasonable use case: user has multiple tools, some that can work with an expanded rom and some that cannot. They want to save what freespace they have below 1000000 for the weaker tools. So HMA needs to be able to put new data into a user-specified freespace (still being safe, of course).
This commit is contained in:
Benjamin Popp 2020-06-05 08:32:24 -05:00
parent 0b3900bba5
commit 7b0c9f06e8
5 changed files with 39 additions and 6 deletions

View File

@ -13,6 +13,11 @@ namespace HavenSoft.HexManiac.Core.Models {
bool HasChanged(int index);
void ResetChanges();
/// <summary>
/// Used during repointing
/// </summary>
int FreeSpaceStart { get; set; }
new byte this[int index] { get; set; }
IReadOnlyList<ArrayRun> Arrays { get; }
IReadOnlyList<IStreamRun> Streams { get; }
@ -76,6 +81,8 @@ namespace HavenSoft.HexManiac.Core.Models {
public BaseModel(byte[] data) => RawData = data;
public int FreeSpaceStart { get; set; }
public virtual IReadOnlyList<ArrayRun> Arrays { get; } = new List<ArrayRun>();
public virtual IReadOnlyList<IStreamRun> Streams { get; } = new List<IStreamRun>();
public virtual IReadOnlyList<string> Anchors { get; } = new List<string>();

View File

@ -58,6 +58,7 @@ namespace HavenSoft.HexManiac.Core.Models {
WriteSpriteRuns(pointersForDestination);
WriteStringRuns(pointersForDestination);
ResolveConflicts();
FreeSpaceStart = EarliestAllowedAnchor;
if (metadata == null) return;
@ -88,6 +89,8 @@ namespace HavenSoft.HexManiac.Core.Models {
}
}
if (metadata.FreeSpaceSearch >= 0) FreeSpaceStart = metadata.FreeSpaceSearch;
ResolveConflicts();
}
@ -914,6 +917,8 @@ namespace HavenSoft.HexManiac.Core.Models {
}
public override int FindFreeSpace(int start, int minimumLength) {
start = FreeSpaceStart;
if (start < EarliestAllowedAnchor) start = EarliestAllowedAnchor;
const int SpacerLength = 0x100;
minimumLength += 0x140; // make sure there's plenty of room after, so that we're not in the middle of some other data set
var runIndex = 0;
@ -940,6 +945,7 @@ namespace HavenSoft.HexManiac.Core.Models {
// found a good spot!
// move the run
FreeSpaceStart = start;
return start;
}
@ -1367,7 +1373,7 @@ namespace HavenSoft.HexManiac.Core.Models {
lists.Add(new StoredList(name, members.ToList()));
}
return new StoredMetadata(anchors, unmappedPointers, matchedWords, lists, metadataInfo);
return new StoredMetadata(anchors, unmappedPointers, matchedWords, lists, metadataInfo, FreeSpaceStart);
}
/// <summary>

View File

@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.ExceptionServices;
namespace HavenSoft.HexManiac.Core.Models {
public class StoredMetadata {
@ -11,15 +12,17 @@ namespace HavenSoft.HexManiac.Core.Models {
public IReadOnlyList<StoredMatchedWord> MatchedWords { get; }
public IReadOnlyList<StoredList> Lists { get; }
public string Version { get; }
public int FreeSpaceSearch { get; } = -1;
public bool IsEmpty => NamedAnchors.Count == 0 && UnmappedPointers.Count == 0;
public StoredMetadata(IReadOnlyList<StoredAnchor> anchors, IReadOnlyList<StoredUnmappedPointer> unmappedPointers, IReadOnlyList<StoredMatchedWord> matchedWords, IReadOnlyList<StoredList> lists, IMetadataInfo generalInfo) {
public StoredMetadata(IReadOnlyList<StoredAnchor> anchors, IReadOnlyList<StoredUnmappedPointer> unmappedPointers, IReadOnlyList<StoredMatchedWord> matchedWords, IReadOnlyList<StoredList> lists, IMetadataInfo generalInfo, int freeSpaceSearch) {
NamedAnchors = anchors ?? new List<StoredAnchor>();
UnmappedPointers = unmappedPointers ?? new List<StoredUnmappedPointer>();
MatchedWords = matchedWords ?? new List<StoredMatchedWord>();
Lists = lists ?? new List<StoredList>();
Version = generalInfo.VersionNumber;
FreeSpaceSearch = freeSpaceSearch;
}
public StoredMetadata(string[] lines) {
@ -65,6 +68,10 @@ namespace HavenSoft.HexManiac.Core.Models {
Version = cleanLine.Split("'''")[1];
}
if (cleanLine.StartsWith("FreeSpaceSearch = '''")) {
if (int.TryParse(cleanLine.Split("'''")[1], out var fss)) FreeSpaceSearch = fss;
}
if (cleanLine.Contains('=') && int.TryParse(cleanLine.Split('=')[0].Trim(), out int currentItemIndex)) {
if (currentItemChildren == null) currentItemChildren = new List<string>();
while (currentItemChildren.Count < currentItemIndex) currentItemChildren.Add(null);
@ -98,6 +105,7 @@ namespace HavenSoft.HexManiac.Core.Models {
"[General]"
};
if (Version != null) lines.Add($"ApplicationVersion = '''{Version}'''");
lines.Add($"FreeSpaceSearch = '''{FreeSpaceSearch}'''");
lines.Add(string.Empty);
lines.Add("#################################");

View File

@ -424,6 +424,14 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
#endregion
public int FreeSpaceStart { get => Model.FreeSpaceStart; set {
if (Model.FreeSpaceStart != value) {
Model.FreeSpaceStart = value;
NotifyPropertyChanged();
}
}
}
private readonly ToolTray tools;
public bool HasTools => true;
public IToolTrayViewModel Tools => tools;
@ -896,10 +904,9 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
return false;
}
var startSearch = (Model as PokemonModel)?.EarliestAllowedAnchor ?? 0;
var length = FormatRunFactory.GetStrategy(pointerSegment.InnerFormat).LengthForNewRun(Model, pointer);
var insert = Model.FindFreeSpace(startSearch, length);
var insert = Model.FindFreeSpace(0, length);
if (insert < 0) {
insert = Model.Count;
Model.ExpandData(CurrentChange, Model.Count + length);
@ -1970,6 +1977,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
currentView = new HexElement[Width, Height];
RequestMenuClose?.Invoke(this, EventArgs.Empty);
NotifyCollectionChanged(ResetArgs);
NotifyPropertyChanged(nameof(FreeSpaceStart));
}
private void RefreshBackingDataFull() {

View File

@ -14,10 +14,14 @@
<DockPanel>
<!-- Bottom Bar -->
<DockPanel DockPanel.Dock="Bottom">
<TextBlock DockPanel.Dock="Left" Text="{Binding SelectedAddress}" MouseRightButtonUp="AddressShowMenu"/>
<Grid HorizontalAlignment="Right">
<TextBlock DockPanel.Dock="Left" Width="200" Text="{Binding SelectedAddress}" MouseRightButtonUp="AddressShowMenu"/>
<Grid HorizontalAlignment="Right" DockPanel.Dock="Right">
<TextBlock Margin="10,0,0,0" Text="{Binding SelectedBytes}" MouseRightButtonUp="BytesShowMenu"/>
</Grid>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<TextBlock Text="Free Space:"/>
<TextBox Text="{Binding FreeSpaceStart, Converter={StaticResource Hex}}" Width="70"/>
</StackPanel>
</DockPanel>
<!-- Tool Headers -->
<StackPanel DockPanel.Dock="Left" Visibility="{Binding HasTools, Converter={StaticResource BoolToVisibility}}">