Implement variable tracking infrastructure
This commit is contained in:
parent
14422eec46
commit
e99f23ee0d
@ -120,7 +120,7 @@ namespace rabi_splitter_WPF
|
||||
this.VariableExportTab.DataContext = variableExportContext;
|
||||
this.VariableExportTab.Initialise(debugContext, variableExportContext);
|
||||
BossEventDebug.DataContext = debugContext;
|
||||
rabiRibiDisplay = new RabiRibiDisplay(mainContext, debugContext, this);
|
||||
rabiRibiDisplay = new RabiRibiDisplay(mainContext, debugContext, variableExportContext, this);
|
||||
memoryThread = new Thread(() =>
|
||||
{
|
||||
while (true)
|
||||
|
@ -10,6 +10,7 @@ namespace rabi_splitter_WPF
|
||||
{
|
||||
private MainContext mainContext;
|
||||
private DebugContext debugContext;
|
||||
private VariableExportContext variableExportContext;
|
||||
private MainWindow mainWindow;
|
||||
|
||||
private RabiRibiState rabiRibiState;
|
||||
@ -20,16 +21,18 @@ namespace rabi_splitter_WPF
|
||||
// Variables used for tracking frequency of memory reads.
|
||||
private static readonly DateTime UNIX_START = new DateTime(1970, 1, 1);
|
||||
private double readFps = -1;
|
||||
long previousFrameMillisecond = -1;
|
||||
private long previousFrameMillisecond = -1;
|
||||
private long lastUpdateMillisecond = -1;
|
||||
|
||||
// internal frame counter.
|
||||
private int memoryReadCount;
|
||||
|
||||
public RabiRibiDisplay(MainContext mainContext, DebugContext debugContext, MainWindow mainWindow)
|
||||
public RabiRibiDisplay(MainContext mainContext, DebugContext debugContext, VariableExportContext variableExportContext, MainWindow mainWindow)
|
||||
{
|
||||
this.rabiRibiState = new RabiRibiState();
|
||||
this.mainContext = mainContext;
|
||||
this.debugContext = debugContext;
|
||||
this.variableExportContext = variableExportContext;
|
||||
this.mainWindow = mainWindow;
|
||||
this.memoryReadCount = 0;
|
||||
StartNewGame();
|
||||
@ -47,6 +50,7 @@ namespace rabi_splitter_WPF
|
||||
UpdateDebugArea(memoryHelper);
|
||||
UpdateEntityData(memoryHelper);
|
||||
UpdateFps();
|
||||
UpdateVariableExport();
|
||||
|
||||
if (snapshot.musicid >= 0) rabiRibiState.lastValidMusicId = snapshot.musicid;
|
||||
prevSnapshot = snapshot;
|
||||
@ -54,6 +58,19 @@ namespace rabi_splitter_WPF
|
||||
memoryHelper.Dispose();
|
||||
}
|
||||
|
||||
private void UpdateVariableExport()
|
||||
{
|
||||
variableExportContext.CheckForUpdates();
|
||||
long currentFrameMillisecond = (long)(DateTime.Now - UNIX_START).TotalMilliseconds;
|
||||
var diff = currentFrameMillisecond - lastUpdateMillisecond;
|
||||
if (diff >= 1000)
|
||||
{
|
||||
if (diff >= 2000) lastUpdateMillisecond = currentFrameMillisecond;
|
||||
else lastUpdateMillisecond += 1000;
|
||||
variableExportContext.OutputUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFps()
|
||||
{
|
||||
long currentFrameMillisecond = (long)(DateTime.Now - UNIX_START).TotalMilliseconds;
|
||||
|
@ -11,12 +11,42 @@ namespace rabi_splitter_WPF
|
||||
public class VariableExportContext : INotifyPropertyChanged
|
||||
{
|
||||
private List<VariableExportSetting> _variableExportSettings;
|
||||
private HashSet<VariableExportSetting> pendingUpdates;
|
||||
|
||||
public VariableExportContext()
|
||||
{
|
||||
_variableExportSettings = new List<VariableExportSetting>();
|
||||
pendingUpdates = new HashSet<VariableExportSetting>();
|
||||
}
|
||||
|
||||
#region Update Logic
|
||||
|
||||
public void OutputUpdates()
|
||||
{
|
||||
foreach (var ves in pendingUpdates)
|
||||
{
|
||||
ves.OutputUpdate();
|
||||
}
|
||||
pendingUpdates.Clear();
|
||||
}
|
||||
|
||||
private void RegisterUpdate(VariableExportSetting ves)
|
||||
{
|
||||
pendingUpdates.Add(ves);
|
||||
}
|
||||
|
||||
public void CheckForUpdates()
|
||||
{
|
||||
foreach (var ves in _variableExportSettings)
|
||||
{
|
||||
bool hasUpdate = ves.CheckForUpdate();
|
||||
if (hasUpdate) RegisterUpdate(ves);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Variables
|
||||
public List<VariableExportSetting> VariableExportSettings
|
||||
{
|
||||
get { return _variableExportSettings; }
|
||||
@ -30,7 +60,9 @@ namespace rabi_splitter_WPF
|
||||
internal void Delete(VariableExportSetting ves)
|
||||
{
|
||||
_variableExportSettings.Remove(ves);
|
||||
pendingUpdates.Remove(ves);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
|
@ -7,14 +7,29 @@ using System.Text;
|
||||
|
||||
namespace rabi_splitter_WPF
|
||||
{
|
||||
public class ExportableVariable
|
||||
public class ExportableVariable<T> : ExportableVariable
|
||||
{
|
||||
private readonly Func<T> tracker;
|
||||
|
||||
public ExportableVariable(string displayName, Func<T> tracker) : base(displayName)
|
||||
{
|
||||
this.tracker = tracker;
|
||||
}
|
||||
|
||||
internal override VariableTracker GetTracker()
|
||||
{
|
||||
return new VariableTracker<T>(tracker);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class ExportableVariable
|
||||
{
|
||||
// Do not make these properties public.
|
||||
private static int nextAvailableId = 0;
|
||||
private readonly int _id;
|
||||
private readonly string _displayName;
|
||||
|
||||
private ExportableVariable(string displayName)
|
||||
protected ExportableVariable(string displayName)
|
||||
{
|
||||
_id = nextAvailableId++;
|
||||
_displayName = displayName;
|
||||
@ -30,11 +45,13 @@ namespace rabi_splitter_WPF
|
||||
get { return _displayName; }
|
||||
}
|
||||
|
||||
internal abstract VariableTracker GetTracker();
|
||||
|
||||
public static List<ExportableVariable> GetAll()
|
||||
{
|
||||
return new List<ExportableVariable>()
|
||||
{
|
||||
new ExportableVariable("TestVariable")
|
||||
new ExportableVariable<int>("TestVariable", () => 1)
|
||||
};
|
||||
}
|
||||
|
||||
@ -53,14 +70,96 @@ namespace rabi_splitter_WPF
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class VariableTracker<T> : VariableTracker
|
||||
{
|
||||
private readonly Func<T> tracker;
|
||||
private T currentValue;
|
||||
|
||||
public VariableTracker(Func<T> tracker)
|
||||
{
|
||||
this.tracker = tracker;
|
||||
forceUpdate = true;
|
||||
}
|
||||
|
||||
public override bool CheckForUpdate()
|
||||
{
|
||||
T newValue = tracker();
|
||||
if (forceUpdate || !newValue.Equals(currentValue))
|
||||
{
|
||||
currentValue = newValue;
|
||||
forceUpdate = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override object GetValue()
|
||||
{
|
||||
return currentValue;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class VariableTracker
|
||||
{
|
||||
protected bool forceUpdate;
|
||||
|
||||
public void FormatChanged()
|
||||
{
|
||||
forceUpdate = true;
|
||||
}
|
||||
|
||||
public abstract bool CheckForUpdate();
|
||||
public abstract object GetValue();
|
||||
}
|
||||
|
||||
public class VariableExportSetting : INotifyPropertyChanged
|
||||
{
|
||||
private ExportableVariable _selectedVariable;
|
||||
private VariableTracker _variableTracker;
|
||||
private string _outputFileName;
|
||||
private string _outputFormat;
|
||||
private string _formatPreview;
|
||||
private bool _isExporting;
|
||||
private bool _isPreviewingFormat;
|
||||
|
||||
public VariableExportSetting()
|
||||
{
|
||||
// Default values
|
||||
_selectedVariable = null;
|
||||
_outputFileName = "";
|
||||
_outputFormat = "";
|
||||
_isExporting = false;
|
||||
_isPreviewingFormat = false;
|
||||
}
|
||||
|
||||
#region Logic
|
||||
private string FormatOutput()
|
||||
{
|
||||
try
|
||||
{
|
||||
return string.Format(_outputFormat, _variableTracker.GetValue());
|
||||
}
|
||||
catch (FormatException e)
|
||||
{
|
||||
return e.Message;
|
||||
}
|
||||
}
|
||||
|
||||
internal void OutputUpdate()
|
||||
{
|
||||
if (_variableTracker == null) return;
|
||||
var formattedOutput = FormatOutput();
|
||||
FormatPreview = formattedOutput;
|
||||
// TODO: Write to file
|
||||
}
|
||||
|
||||
internal bool CheckForUpdate()
|
||||
{
|
||||
if (_variableTracker == null) return false;
|
||||
return _variableTracker.CheckForUpdate();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Dictionaries
|
||||
private static Dictionary<ExportableVariable, string> _variableCaptions;
|
||||
|
||||
@ -83,16 +182,6 @@ namespace rabi_splitter_WPF
|
||||
|
||||
#endregion
|
||||
|
||||
public VariableExportSetting()
|
||||
{
|
||||
// Default values
|
||||
_selectedVariable = null;
|
||||
_outputFileName = "";
|
||||
_outputFormat = "";
|
||||
_isExporting = false;
|
||||
_isPreviewingFormat = false;
|
||||
}
|
||||
|
||||
#region Parameters
|
||||
|
||||
public ExportableVariable SelectedVariable
|
||||
@ -102,6 +191,7 @@ namespace rabi_splitter_WPF
|
||||
{
|
||||
if (value.Equals(_selectedVariable)) return;
|
||||
_selectedVariable = value;
|
||||
_variableTracker = _selectedVariable.GetTracker();
|
||||
OnPropertyChanged(nameof(SelectedVariable));
|
||||
}
|
||||
}
|
||||
@ -124,10 +214,22 @@ namespace rabi_splitter_WPF
|
||||
{
|
||||
if (value.Equals(_outputFormat)) return;
|
||||
_outputFormat = value;
|
||||
if (_variableTracker != null) _variableTracker.FormatChanged();
|
||||
OnPropertyChanged(nameof(OutputFormat));
|
||||
}
|
||||
}
|
||||
|
||||
public string FormatPreview
|
||||
{
|
||||
get { return _formatPreview; }
|
||||
private set
|
||||
{
|
||||
if (value.Equals(_formatPreview)) return;
|
||||
_formatPreview = value;
|
||||
OnPropertyChanged(nameof(FormatPreview));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsPreviewingFormat
|
||||
{
|
||||
get { return _isPreviewingFormat; }
|
||||
@ -149,10 +251,10 @@ namespace rabi_splitter_WPF
|
||||
OnPropertyChanged(nameof(IsExporting));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
// Note: DO NOT OVERRIDE Equals and GetHashCode. We compare by reference equality.
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
@ -160,6 +262,5 @@ namespace rabi_splitter_WPF
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@
|
||||
<Button Grid.Column="2" Content="Default" Click="DefaultButton_Click"/>
|
||||
</Grid>
|
||||
<TextBox Height="50" DockPanel.Dock="Top" Margin="0,5,0,5" Text="{Binding Path=OutputFormat, Mode=TwoWay}" AcceptsReturn="True" Visibility="{Binding Path=IsPreviewingFormat, Converter={StaticResource InvertableBooleanToVisibilityConverter}, ConverterParameter=VisibleWhenFalse, FallbackValue=Visible}"/>
|
||||
<TextBlock Height="50" DockPanel.Dock="Top" Margin="0,5,0,5" Text="{Binding Path=OutputFormat, Mode=TwoWay}" Visibility="{Binding Path=IsPreviewingFormat, Converter={StaticResource InvertableBooleanToVisibilityConverter}, ConverterParameter=VisibleWhenTrue, FallbackValue=Collapsed}"/>
|
||||
<TextBlock Height="50" DockPanel.Dock="Top" Margin="0,5,0,5" Text="{Binding Path=FormatPreview}" Visibility="{Binding Path=IsPreviewingFormat, Converter={StaticResource InvertableBooleanToVisibilityConverter}, ConverterParameter=VisibleWhenTrue, FallbackValue=Collapsed}"/>
|
||||
</DockPanel>
|
||||
</DockPanel>
|
||||
<DockPanel Grid.Column="2">
|
||||
|
Loading…
x
Reference in New Issue
Block a user