Implement variable tracking infrastructure

rabi_display
wcko87 8 years ago
parent 14422eec46
commit e99f23ee0d
  1. 2
      rabi_splitter_WPF/MainWindow.xaml.cs
  2. 21
      rabi_splitter_WPF/RabiRibiDisplay.cs
  3. 32
      rabi_splitter_WPF/VariableExportContext.cs
  4. 133
      rabi_splitter_WPF/VariableExportSetting.cs
  5. 2
      rabi_splitter_WPF/VariableExportTab.xaml

@ -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…
Cancel
Save