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.DataContext = variableExportContext;
|
||||||
this.VariableExportTab.Initialise(debugContext, variableExportContext);
|
this.VariableExportTab.Initialise(debugContext, variableExportContext);
|
||||||
BossEventDebug.DataContext = debugContext;
|
BossEventDebug.DataContext = debugContext;
|
||||||
rabiRibiDisplay = new RabiRibiDisplay(mainContext, debugContext, this);
|
rabiRibiDisplay = new RabiRibiDisplay(mainContext, debugContext, variableExportContext, this);
|
||||||
memoryThread = new Thread(() =>
|
memoryThread = new Thread(() =>
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
|
@ -10,6 +10,7 @@ namespace rabi_splitter_WPF
|
|||||||
{
|
{
|
||||||
private MainContext mainContext;
|
private MainContext mainContext;
|
||||||
private DebugContext debugContext;
|
private DebugContext debugContext;
|
||||||
|
private VariableExportContext variableExportContext;
|
||||||
private MainWindow mainWindow;
|
private MainWindow mainWindow;
|
||||||
|
|
||||||
private RabiRibiState rabiRibiState;
|
private RabiRibiState rabiRibiState;
|
||||||
@ -20,16 +21,18 @@ namespace rabi_splitter_WPF
|
|||||||
// Variables used for tracking frequency of memory reads.
|
// Variables used for tracking frequency of memory reads.
|
||||||
private static readonly DateTime UNIX_START = new DateTime(1970, 1, 1);
|
private static readonly DateTime UNIX_START = new DateTime(1970, 1, 1);
|
||||||
private double readFps = -1;
|
private double readFps = -1;
|
||||||
long previousFrameMillisecond = -1;
|
private long previousFrameMillisecond = -1;
|
||||||
|
private long lastUpdateMillisecond = -1;
|
||||||
|
|
||||||
// internal frame counter.
|
// internal frame counter.
|
||||||
private int memoryReadCount;
|
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.rabiRibiState = new RabiRibiState();
|
||||||
this.mainContext = mainContext;
|
this.mainContext = mainContext;
|
||||||
this.debugContext = debugContext;
|
this.debugContext = debugContext;
|
||||||
|
this.variableExportContext = variableExportContext;
|
||||||
this.mainWindow = mainWindow;
|
this.mainWindow = mainWindow;
|
||||||
this.memoryReadCount = 0;
|
this.memoryReadCount = 0;
|
||||||
StartNewGame();
|
StartNewGame();
|
||||||
@ -47,6 +50,7 @@ namespace rabi_splitter_WPF
|
|||||||
UpdateDebugArea(memoryHelper);
|
UpdateDebugArea(memoryHelper);
|
||||||
UpdateEntityData(memoryHelper);
|
UpdateEntityData(memoryHelper);
|
||||||
UpdateFps();
|
UpdateFps();
|
||||||
|
UpdateVariableExport();
|
||||||
|
|
||||||
if (snapshot.musicid >= 0) rabiRibiState.lastValidMusicId = snapshot.musicid;
|
if (snapshot.musicid >= 0) rabiRibiState.lastValidMusicId = snapshot.musicid;
|
||||||
prevSnapshot = snapshot;
|
prevSnapshot = snapshot;
|
||||||
@ -54,6 +58,19 @@ namespace rabi_splitter_WPF
|
|||||||
memoryHelper.Dispose();
|
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()
|
private void UpdateFps()
|
||||||
{
|
{
|
||||||
long currentFrameMillisecond = (long)(DateTime.Now - UNIX_START).TotalMilliseconds;
|
long currentFrameMillisecond = (long)(DateTime.Now - UNIX_START).TotalMilliseconds;
|
||||||
|
@ -11,12 +11,42 @@ namespace rabi_splitter_WPF
|
|||||||
public class VariableExportContext : INotifyPropertyChanged
|
public class VariableExportContext : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
private List<VariableExportSetting> _variableExportSettings;
|
private List<VariableExportSetting> _variableExportSettings;
|
||||||
|
private HashSet<VariableExportSetting> pendingUpdates;
|
||||||
|
|
||||||
public VariableExportContext()
|
public VariableExportContext()
|
||||||
{
|
{
|
||||||
_variableExportSettings = new List<VariableExportSetting>();
|
_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
|
public List<VariableExportSetting> VariableExportSettings
|
||||||
{
|
{
|
||||||
get { return _variableExportSettings; }
|
get { return _variableExportSettings; }
|
||||||
@ -30,7 +60,9 @@ namespace rabi_splitter_WPF
|
|||||||
internal void Delete(VariableExportSetting ves)
|
internal void Delete(VariableExportSetting ves)
|
||||||
{
|
{
|
||||||
_variableExportSettings.Remove(ves);
|
_variableExportSettings.Remove(ves);
|
||||||
|
pendingUpdates.Remove(ves);
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
@ -7,14 +7,29 @@ using System.Text;
|
|||||||
|
|
||||||
namespace rabi_splitter_WPF
|
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.
|
// Do not make these properties public.
|
||||||
private static int nextAvailableId = 0;
|
private static int nextAvailableId = 0;
|
||||||
private readonly int _id;
|
private readonly int _id;
|
||||||
private readonly string _displayName;
|
private readonly string _displayName;
|
||||||
|
|
||||||
private ExportableVariable(string displayName)
|
protected ExportableVariable(string displayName)
|
||||||
{
|
{
|
||||||
_id = nextAvailableId++;
|
_id = nextAvailableId++;
|
||||||
_displayName = displayName;
|
_displayName = displayName;
|
||||||
@ -30,11 +45,13 @@ namespace rabi_splitter_WPF
|
|||||||
get { return _displayName; }
|
get { return _displayName; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal abstract VariableTracker GetTracker();
|
||||||
|
|
||||||
public static List<ExportableVariable> GetAll()
|
public static List<ExportableVariable> GetAll()
|
||||||
{
|
{
|
||||||
return new List<ExportableVariable>()
|
return new List<ExportableVariable>()
|
||||||
{
|
{
|
||||||
new ExportableVariable("TestVariable")
|
new ExportableVariable<int>("TestVariable", () => 1)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,14 +70,96 @@ namespace rabi_splitter_WPF
|
|||||||
#endregion
|
#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
|
public class VariableExportSetting : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
private ExportableVariable _selectedVariable;
|
private ExportableVariable _selectedVariable;
|
||||||
|
private VariableTracker _variableTracker;
|
||||||
private string _outputFileName;
|
private string _outputFileName;
|
||||||
private string _outputFormat;
|
private string _outputFormat;
|
||||||
|
private string _formatPreview;
|
||||||
private bool _isExporting;
|
private bool _isExporting;
|
||||||
private bool _isPreviewingFormat;
|
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
|
#region Dictionaries
|
||||||
private static Dictionary<ExportableVariable, string> _variableCaptions;
|
private static Dictionary<ExportableVariable, string> _variableCaptions;
|
||||||
|
|
||||||
@ -83,16 +182,6 @@ namespace rabi_splitter_WPF
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public VariableExportSetting()
|
|
||||||
{
|
|
||||||
// Default values
|
|
||||||
_selectedVariable = null;
|
|
||||||
_outputFileName = "";
|
|
||||||
_outputFormat = "";
|
|
||||||
_isExporting = false;
|
|
||||||
_isPreviewingFormat = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Parameters
|
#region Parameters
|
||||||
|
|
||||||
public ExportableVariable SelectedVariable
|
public ExportableVariable SelectedVariable
|
||||||
@ -102,6 +191,7 @@ namespace rabi_splitter_WPF
|
|||||||
{
|
{
|
||||||
if (value.Equals(_selectedVariable)) return;
|
if (value.Equals(_selectedVariable)) return;
|
||||||
_selectedVariable = value;
|
_selectedVariable = value;
|
||||||
|
_variableTracker = _selectedVariable.GetTracker();
|
||||||
OnPropertyChanged(nameof(SelectedVariable));
|
OnPropertyChanged(nameof(SelectedVariable));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,10 +214,22 @@ namespace rabi_splitter_WPF
|
|||||||
{
|
{
|
||||||
if (value.Equals(_outputFormat)) return;
|
if (value.Equals(_outputFormat)) return;
|
||||||
_outputFormat = value;
|
_outputFormat = value;
|
||||||
|
if (_variableTracker != null) _variableTracker.FormatChanged();
|
||||||
OnPropertyChanged(nameof(OutputFormat));
|
OnPropertyChanged(nameof(OutputFormat));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string FormatPreview
|
||||||
|
{
|
||||||
|
get { return _formatPreview; }
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
if (value.Equals(_formatPreview)) return;
|
||||||
|
_formatPreview = value;
|
||||||
|
OnPropertyChanged(nameof(FormatPreview));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsPreviewingFormat
|
public bool IsPreviewingFormat
|
||||||
{
|
{
|
||||||
get { return _isPreviewingFormat; }
|
get { return _isPreviewingFormat; }
|
||||||
@ -149,10 +251,10 @@ namespace rabi_splitter_WPF
|
|||||||
OnPropertyChanged(nameof(IsExporting));
|
OnPropertyChanged(nameof(IsExporting));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
// Note: DO NOT OVERRIDE Equals and GetHashCode. We compare by reference equality.
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
[NotifyPropertyChangedInvocator]
|
[NotifyPropertyChangedInvocator]
|
||||||
@ -160,6 +262,5 @@ namespace rabi_splitter_WPF
|
|||||||
{
|
{
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
<Button Grid.Column="2" Content="Default" Click="DefaultButton_Click"/>
|
<Button Grid.Column="2" Content="Default" Click="DefaultButton_Click"/>
|
||||||
</Grid>
|
</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}"/>
|
<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>
|
</DockPanel>
|
||||||
<DockPanel Grid.Column="2">
|
<DockPanel Grid.Column="2">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user