map editor support text, flags, and item with complex scripts

This commit is contained in:
haven1433 2025-12-13 17:40:03 -06:00
parent aae25c2383
commit 7ae7a58226
7 changed files with 655 additions and 756 deletions

File diff suppressed because it is too large Load Diff

View File

@ -219,7 +219,7 @@ namespace HavenSoft.HexManiac.Core.Models.Code {
private Dictionary<string, List<IScriptLine>> tableDependencyCache = new();
public IEnumerable<IScriptLine> DependsOn(string basename) {
if (tableDependencyCache.ContainsKey(basename)) return tableDependencyCache[basename];
lock (tableDependencyCache) if (tableDependencyCache.ContainsKey(basename)) return tableDependencyCache[basename];
var matches = new List<IScriptLine>();
foreach (var line in engine) {
foreach (var arg in line.Args) {
@ -229,7 +229,7 @@ namespace HavenSoft.HexManiac.Core.Models.Code {
}
}
}
return tableDependencyCache[basename] = matches;
lock (tableDependencyCache) return tableDependencyCache[basename] = matches;
}
private HashSet<string> constantCache, keywordCache;

View File

@ -88,6 +88,7 @@ namespace HavenSoft.HexManiac.Core.Models {
void ClearFormat(ModelDelta changeToken, int start, int length);
void ClearData(ModelDelta changeToken, int start, int length);
void ClearFormatAndData(ModelDelta changeToken, int start, int length);
void ClearCacheScope();
void SetList(ModelDelta changeToken, string name, IEnumerable<string> list, IReadOnlyDictionary<int, string> comments, string hash);
void UpdateGotoShortcut(int index, GotoShortcutModel shortcut);
void ClearPointer(ModelDelta currentChange, int source, int destination);
@ -142,7 +143,7 @@ namespace HavenSoft.HexManiac.Core.Models {
public byte[] RawData { get; private set; }
private ModelCacheScope currentCacheScope;
protected void ClearCacheScope() => currentCacheScope = null;
public void ClearCacheScope() => currentCacheScope = null;
public ModelCacheScope CurrentCacheScope {
get {
var instance = currentCacheScope;

View File

@ -1495,7 +1495,7 @@ namespace HavenSoft.HexManiac.Core.Models {
if (existingRun == null || existingRun.Start != run.Start) {
// no format starts exactly at this anchor, so clear any format that goes over this anchor.
ClearFormat(changeToken, location, run.Length);
} else if (!(run is NoInfoRun)) {
} else if (run is not NoInfoRun) {
// a format starts exactly at this anchor.
if (existingRun.Length < run.Length) {
// the new format may extend further. Clear excess space to make room for the longer format.

View File

@ -1348,8 +1348,26 @@ show:
);
public ObservableCollection<EventTextViewModel> BasicText { get; } = new();
public ObservableCollection<int> BasicItemAddresses { get; } = new();
public ObservableCollection<int> BasicFlagAddresses { get; } = new();
private int basicFlag = -1;
public FilteringComboOptions BasicItem { get; } = new();
public bool HasBasicItem => (BasicItem.AllOptions?.Count ?? 0) > 0;
public int BasicFlag { get => basicFlag; set => Set(ref basicFlag, value, old => NotifyPropertyChanged(nameof(HasBasicFlag))); }
public bool HasBasicFlag => basicFlag != -1;
private string basicFlagText = string.Empty;
public string BasicFlagText {
get => basicFlagText;
set => Set(ref basicFlagText, value, old => {
if (!basicFlagText.TryParseHex(out int result)) return;
foreach (var address in BasicFlagAddresses) element.Model.WriteMultiByteValue(address, 2, Token, result);
basicFlag = result;
NotifyPropertyChanged(nameof(BasicFlag));
});
}
private void FillBasicContent() {
// text
BasicText.Clear();
foreach (var spot in Flags.GetAllScriptSpots(Element.Model, parser, new[] { ScriptAddress }, 0x0F)) {
var element = new EventTextViewModel() { PointerAddress = spot.Address + 2, Text = { Content = GetText(spot.Address + 2) } };
@ -1360,11 +1378,56 @@ show:
BasicText.Add(element);
}
// items
BasicItemAddresses.Clear();
var filter = new List<byte>();
foreach (var line in parser.DependsOn(HardcodeTablesModel.ItemsTableName)) {
if (line is MacroScriptLine macro && macro.Args[0] is SilentMatchArg silent) filter.Add(silent.ExpectedValue);
if (line is ScriptLine sl) filter.Add(line.LineCode[0]);
}
var spots = new List<int>();
var item = -1;
foreach (var spot in Flags.GetAllScriptSpots(element.Model, parser, new[] { ScriptAddress }, true, filter.ToArray())) {
var offset = spot.Address + spot.Line.Args.Until(arg => arg.EnumTableName == HardcodeTablesModel.ItemsTableName).Sum(arg => arg.Length(Element.Model, -1)) + spot.Line.LineCode.Count;
var chosenItem = Element.Model.ReadMultiByteValue(offset, 2);
if (item == -1 || item == chosenItem) {
item = chosenItem;
spots.Add(offset);
} else {
spots.Clear();
break;
}
}
if (spots.Count > 0) {
BasicItem.Update(ComboOption.Convert(element.Model.GetOptions(HardcodeTablesModel.ItemsTableName)), item);
foreach (var address in spots.Distinct()) BasicItemAddresses.Add(address);
BasicItem.Bind(nameof(BasicItem.SelectedIndex), (sender, e) => {
foreach (var address in BasicItemAddresses) element.Model.WriteMultiByteValue(address, 2, Token, sender.SelectedIndex);
});
}
// flags
BasicFlagAddresses.Clear();
spots.Clear();
var flag = -1;
foreach (var spot in Flags.GetAllScriptSpots(element.Model, parser, new[] { ScriptAddress }, false, 0x29, 0x2A, 0x2B)) { // setflag, clearflag, checkflag
var offset = spot.Address + 1;
var chosenFlag = element.Model.ReadMultiByteValue(offset, 2);
if (flag == -1 || flag == chosenFlag) {
flag = chosenFlag;
spots.Add(offset);
} else {
spots.Clear();
break;
}
}
if (spots.Count > 0) {
BasicFlag = flag;
foreach (var address in spots.Distinct()) BasicFlagAddresses.Add(address);
basicFlagText = flag.ToString("X4");
}
}
#endregion
private string GetText(ref string cache, int? pointer) {

View File

@ -1439,6 +1439,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
public void Refresh() {
scroll.DataLength = Model.Count;
Model.ClearCacheScope();
var selectionStart = ConvertViewPointToAddress(SelectionStart);
if (selectionStart > Model.Count + 1) SelectionStart = ConvertAddressToViewPoint(Model.Count + 1);
scroll.UpdateHeaders();
@ -1447,6 +1448,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
Tools?.TableTool.DataForCurrentRunChanged();
Tools?.SpriteTool.DataForCurrentRunChanged();
Tools?.CodeTool.ClearConstantCache();
Tools?.CodeTool.DataForCurrentRunChanged();
UpdateAnchorText(ConvertViewPointToAddress(SelectionStart));
}

View File

@ -762,6 +762,22 @@
</Decorator>
</StackPanel>
</Border>
<Grid Visibility="{Binding HasBasicFlag, Converter={StaticResource BoolToVisibility}}">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<local:AngleBorder Direction="Left" Content="Flag:" />
<local:AngleTextBox Grid.Column="1" Direction="Out" TextBinding="{Binding BasicFlagText, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
<Grid Visibility="{Binding HasBasicItem, Converter={StaticResource BoolToVisibility}}">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<local:AngleBorder Direction="Left" Content="Item:" />
<local:AngleComboBox Grid.Column="1" Direction="Out" DataContext="{Binding BasicItem}" />
</Grid>
<ItemsControl ItemsSource="{Binding BasicText}">
<ItemsControl.ItemTemplate>
<DataTemplate>