Refactor IControlMainform handling in Mainform (#3935)

This allows any loaded tool to control any aspect of `IControlMainform` independently of others. Also improves rewinder handling when any tool `WantsToControlRewind`.
This commit is contained in:
Moritz Bender 2024-06-20 19:16:11 +02:00 committed by GitHub
parent 1a9e5e52f1
commit 256218305b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 59 additions and 58 deletions

View File

@ -78,9 +78,6 @@ namespace BizHawk.Client.EmuHawk
bool BlockFrameAdvance { get; set; } bool BlockFrameAdvance { get; set; }
/// <remarks>only referenced from <see cref="TAStudio"/></remarks>
void RelinquishControl(IControlMainform master);
/// <remarks>only referenced from <see cref="TAStudio"/></remarks> /// <remarks>only referenced from <see cref="TAStudio"/></remarks>
void SeekFrameAdvance(); void SeekFrameAdvance();
@ -88,9 +85,6 @@ namespace BizHawk.Client.EmuHawk
bool StartNewMovie(IMovie movie, bool record); bool StartNewMovie(IMovie movie, bool record);
/// <remarks>only referenced from <see cref="TAStudio"/></remarks>
void TakeBackControl();
/// <remarks>only referenced from <see cref="BasicBot"/></remarks> /// <remarks>only referenced from <see cref="BasicBot"/></remarks>
void Throttle(); void Throttle();

View File

@ -100,9 +100,9 @@ namespace BizHawk.Client.EmuHawk
public void StopMovie(bool saveChanges = true) public void StopMovie(bool saveChanges = true)
{ {
if (IsSlave && Master.WantsToControlStopMovie) if (ToolControllingStopMovie is { } tool)
{ {
Master.StopMovie(!saveChanges); tool.StopMovie(!saveChanges);
} }
else else
{ {
@ -113,7 +113,7 @@ namespace BizHawk.Client.EmuHawk
public bool RestartMovie() public bool RestartMovie()
{ {
if (IsSlave && Master.WantsToControlRestartMovie) return Master.RestartMovie(); if (ToolControllingRestartMovie is { } tool) return tool.RestartMovie();
if (!MovieSession.Movie.IsActive()) return false; if (!MovieSession.Movie.IsActive()) return false;
var success = StartNewMovie(MovieSession.Movie, false); var success = StartNewMovie(MovieSession.Movie, false);
if (success) AddOnScreenMessage("Replaying movie file in read-only mode"); if (success) AddOnScreenMessage("Replaying movie file in read-only mode");
@ -122,9 +122,9 @@ namespace BizHawk.Client.EmuHawk
private void ToggleReadOnly() private void ToggleReadOnly()
{ {
if (IsSlave && Master.WantsToControlReadOnly) if (ToolControllingReadOnly is { } tool)
{ {
Master.ToggleReadOnly(); tool.ToggleReadOnly();
} }
else else
{ {

View File

@ -1089,6 +1089,13 @@ namespace BizHawk.Client.EmuHawk
public readonly ToolManager Tools; public readonly ToolManager Tools;
private IControlMainform ToolControllingSavestates => Tools.FirstOrNull<IControlMainform>(tool => tool.WantsToControlSavestates);
private IControlMainform ToolControllingRewind => Tools.FirstOrNull<IControlMainform>(tool => tool.WantsToControlRewind);
private IControlMainform ToolControllingReboot => Tools.FirstOrNull<IControlMainform>(tool => tool.WantsToControlReboot);
private IControlMainform ToolControllingStopMovie => Tools.FirstOrNull<IControlMainform>(tool => tool.WantsToControlStopMovie);
private IControlMainform ToolControllingRestartMovie => Tools.FirstOrNull<IControlMainform>(tool => tool.WantsToControlRestartMovie);
private IControlMainform ToolControllingReadOnly => Tools.FirstOrNull<IControlMainform>(tool => tool.WantsToControlReadOnly);
private DisplayManager DisplayManager; private DisplayManager DisplayManager;
private OSDManager OSD => DisplayManager.OSD; private OSDManager OSD => DisplayManager.OSD;
@ -1116,6 +1123,8 @@ namespace BizHawk.Client.EmuHawk
public void CreateRewinder() public void CreateRewinder()
{ {
if (ToolControllingRewind is not null) return;
Rewinder?.Dispose(); Rewinder?.Dispose();
Rewinder = Emulator.HasSavestates() && Config.Rewind.Enabled && (!Emulator.AsStatable().AvoidRewind || Config.Rewind.AllowSlowStates) Rewinder = Emulator.HasSavestates() && Config.Rewind.Enabled && (!Emulator.AsStatable().AvoidRewind || Config.Rewind.AllowSlowStates)
? Config.Rewind.UseDelta ? Config.Rewind.UseDelta
@ -1274,9 +1283,9 @@ namespace BizHawk.Client.EmuHawk
public bool RebootCore() public bool RebootCore()
{ {
if (IsSlave && Master.WantsToControlReboot) if (ToolControllingReboot is { } tool)
{ {
Master.RebootCore(); tool.RebootCore();
return true; return true;
} }
else else
@ -3257,7 +3266,7 @@ namespace BizHawk.Client.EmuHawk
MovieSession.Movie.SwitchToRecord(); MovieSession.Movie.SwitchToRecord();
} }
if (isRewinding && !IsRewindSlave && MovieSession.Movie.IsRecording()) if (isRewinding && ToolControllingRewind is null && MovieSession.Movie.IsRecording())
{ {
MovieSession.Movie.Truncate(Emulator.Frame); MovieSession.Movie.Truncate(Emulator.Frame);
} }
@ -4175,7 +4184,6 @@ namespace BizHawk.Client.EmuHawk
Emulator.Dispose(); Emulator.Dispose();
Emulator = new NullEmulator(); Emulator = new NullEmulator();
Game = GameInfo.NullInstance; Game = GameInfo.NullInstance;
CreateRewinder();
Tools.Restart(Config, Emulator, Game); Tools.Restart(Config, Emulator, Game);
RewireSound(); RewireSound();
ClearHolds(); ClearHolds();
@ -4248,25 +4256,6 @@ namespace BizHawk.Client.EmuHawk
Rewinder = null; Rewinder = null;
} }
// TODO: move me
public IControlMainform Master { get; private set; }
private bool IsSlave => Master != null;
private bool IsSavestateSlave => IsSlave && Master.WantsToControlSavestates;
private bool IsRewindSlave => IsSlave && Master.WantsToControlRewind;
public void RelinquishControl(IControlMainform master)
{
Master = master;
}
public void TakeBackControl()
{
Master = null;
}
private int SlotToInt(string slot) private int SlotToInt(string slot)
{ {
return int.Parse(slot.Substring(slot.Length - 1, 1)); return int.Parse(slot.Substring(slot.Length - 1, 1));
@ -4282,7 +4271,7 @@ namespace BizHawk.Client.EmuHawk
public bool LoadState(string path, string userFriendlyStateName, bool suppressOSD = false) // Move to client.common public bool LoadState(string path, string userFriendlyStateName, bool suppressOSD = false) // Move to client.common
{ {
if (!Emulator.HasSavestates()) return false; if (!Emulator.HasSavestates()) return false;
if (IsSavestateSlave) return Master.LoadState(); if (ToolControllingSavestates is { } tool) return tool.LoadState();
if (!new SavestateFile(Emulator, MovieSession, MovieSession.UserBag).Load(path, this)) if (!new SavestateFile(Emulator, MovieSession, MovieSession.UserBag).Load(path, this))
{ {
@ -4311,7 +4300,7 @@ namespace BizHawk.Client.EmuHawk
//we don't want to analyze how to intermix movies, rewinding, and states //we don't want to analyze how to intermix movies, rewinding, and states
//so purge rewind history when loading a state while doing a movie //so purge rewind history when loading a state while doing a movie
if (!IsRewindSlave && MovieSession.Movie.IsActive()) if (ToolControllingRewind is null && MovieSession.Movie.IsActive())
{ {
Rewinder?.Clear(); Rewinder?.Clear();
} }
@ -4337,7 +4326,7 @@ namespace BizHawk.Client.EmuHawk
} }
if (handled) return true; // not sure if (handled) return true; // not sure
if (IsSavestateSlave) return Master.LoadQuickSave(SlotToInt(quickSlotName)); if (ToolControllingSavestates is { } tool) return tool.LoadQuickSave(SlotToInt(quickSlotName));
var path = $"{SaveStatePrefix()}.{quickSlotName}.State"; var path = $"{SaveStatePrefix()}.{quickSlotName}.State";
if (!File.Exists(path)) if (!File.Exists(path))
@ -4356,9 +4345,9 @@ namespace BizHawk.Client.EmuHawk
return; return;
} }
if (IsSavestateSlave) if (ToolControllingSavestates is { } tool)
{ {
Master.SaveState(); tool.SaveState();
return; return;
} }
@ -4409,9 +4398,9 @@ namespace BizHawk.Client.EmuHawk
return; return;
} }
if (IsSavestateSlave) if (ToolControllingSavestates is { } tool)
{ {
Master.SaveQuickSave(SlotToInt(quickSlotName)); tool.SaveQuickSave(SlotToInt(quickSlotName));
return; return;
} }
@ -4482,9 +4471,9 @@ namespace BizHawk.Client.EmuHawk
Tools.TAStudio.NamedStatePending = true; Tools.TAStudio.NamedStatePending = true;
} }
if (IsSavestateSlave) if (ToolControllingSavestates is { } tool)
{ {
Master.SaveStateAs(); tool.SaveStateAs();
return; return;
} }
@ -4512,7 +4501,7 @@ namespace BizHawk.Client.EmuHawk
private bool LoadStateAs() private bool LoadStateAs()
{ {
if (!Emulator.HasSavestates()) return false; if (!Emulator.HasSavestates()) return false;
if (IsSavestateSlave) return Master.LoadStateAs(); if (ToolControllingSavestates is { } tool) return tool.LoadStateAs();
var result = this.ShowFileOpenDialog( var result = this.ShowFileOpenDialog(
discardCWDChange: true, discardCWDChange: true,
@ -4525,9 +4514,9 @@ namespace BizHawk.Client.EmuHawk
private void SelectSlot(int slot) private void SelectSlot(int slot)
{ {
if (!Emulator.HasSavestates()) return; if (!Emulator.HasSavestates()) return;
if (IsSavestateSlave) if (ToolControllingSavestates is { } tool)
{ {
var handled = Master.SelectSlot(slot); bool handled = tool.SelectSlot(slot);
if (handled) return; if (handled) return;
} }
Config.SaveSlot = slot; Config.SaveSlot = slot;
@ -4538,9 +4527,9 @@ namespace BizHawk.Client.EmuHawk
private void PreviousSlot() private void PreviousSlot()
{ {
if (!Emulator.HasSavestates()) return; if (!Emulator.HasSavestates()) return;
if (IsSavestateSlave) if (ToolControllingSavestates is { } tool)
{ {
var handled = Master.PreviousSlot(); bool handled = tool.PreviousSlot();
if (handled) return; if (handled) return;
} }
Config.SaveSlot--; Config.SaveSlot--;
@ -4552,9 +4541,9 @@ namespace BizHawk.Client.EmuHawk
private void NextSlot() private void NextSlot()
{ {
if (!Emulator.HasSavestates()) return; if (!Emulator.HasSavestates()) return;
if (IsSavestateSlave) if (ToolControllingSavestates is { } tool)
{ {
var handled = Master.NextSlot(); bool handled = tool.NextSlot();
if (handled) return; if (handled) return;
} }
Config.SaveSlot++; Config.SaveSlot++;
@ -4565,9 +4554,9 @@ namespace BizHawk.Client.EmuHawk
private void CaptureRewind(bool suppressCaptureRewind) private void CaptureRewind(bool suppressCaptureRewind)
{ {
if (IsRewindSlave) if (ToolControllingRewind is { } tool)
{ {
Master.CaptureRewind(); tool.CaptureRewind();
} }
else if (!suppressCaptureRewind && Rewinder?.Active == true) else if (!suppressCaptureRewind && Rewinder?.Active == true)
{ {
@ -4581,7 +4570,7 @@ namespace BizHawk.Client.EmuHawk
returnToRecording = false; returnToRecording = false;
if (IsRewindSlave) if (ToolControllingRewind is { } rewindTool)
{ {
if (InputManager.ClientControls["Rewind"] || PressRewind) if (InputManager.ClientControls["Rewind"] || PressRewind)
{ {
@ -4620,7 +4609,7 @@ namespace BizHawk.Client.EmuHawk
if (isRewinding) if (isRewinding)
{ {
runFrame = Emulator.Frame > 1; // TODO: the master should be deciding this! runFrame = Emulator.Frame > 1; // TODO: the master should be deciding this!
Master.Rewind(); rewindTool.Rewind();
} }
} }
else else

View File

@ -68,7 +68,7 @@
} }
} }
public bool WantsToControlRewind => true; public bool WantsToControlRewind { get; private set; } = true;
public void CaptureRewind() public void CaptureRewind()
{ {

View File

@ -281,7 +281,6 @@ namespace BizHawk.Client.EmuHawk
MainForm.AddOnScreenMessage("TAStudio engaged"); MainForm.AddOnScreenMessage("TAStudio engaged");
SetTasMovieCallbacks(CurrentTasMovie); SetTasMovieCallbacks(CurrentTasMovie);
UpdateWindowTitle(); UpdateWindowTitle();
MainForm.RelinquishControl(this);
_originalEndAction = Config.Movies.MovieEndAction; _originalEndAction = Config.Movies.MovieEndAction;
MainForm.DisableRewind(); MainForm.DisableRewind();
Config.Movies.MovieEndAction = MovieEndAction.Record; Config.Movies.MovieEndAction = MovieEndAction.Record;
@ -732,8 +731,8 @@ namespace BizHawk.Client.EmuHawk
_engaged = false; _engaged = false;
MainForm.PauseOnFrame = null; MainForm.PauseOnFrame = null;
MainForm.AddOnScreenMessage("TAStudio disengaged"); MainForm.AddOnScreenMessage("TAStudio disengaged");
MainForm.TakeBackControl();
Config.Movies.MovieEndAction = _originalEndAction; Config.Movies.MovieEndAction = _originalEndAction;
WantsToControlRewind = false;
MainForm.EnableRewind(true); MainForm.EnableRewind(true);
MainForm.SetMainformMovieInfo(); MainForm.SetMainformMovieInfo();
} }

View File

@ -473,6 +473,25 @@ namespace BizHawk.Client.EmuHawk
return Load<T>(false); return Load<T>(false);
} }
/// <summary>
/// Returns the first tool of type <typeparamref name="T"/> that fulfills the given condition
/// </summary>
/// <param name="condition">The condition to check for</param>
/// <typeparam name="T">Type of tools to check</typeparam>
/// <returns></returns>
public T FirstOrNull<T>(Predicate<T> condition) where T : class
{
foreach (var tool in _tools)
{
if (tool.IsActive && tool is T specialTool && condition(specialTool))
{
return specialTool;
}
}
return null;
}
/// <summary> /// <summary>
/// returns the instance of <paramref name="toolType"/>, regardless of whether it's loaded,<br/> /// returns the instance of <paramref name="toolType"/>, regardless of whether it's loaded,<br/>
/// but doesn't create and load a new instance if it's not found /// but doesn't create and load a new instance if it's not found
@ -482,7 +501,7 @@ namespace BizHawk.Client.EmuHawk
/// you may pass any class or interface /// you may pass any class or interface
/// </remarks> /// </remarks>
public IToolForm/*?*/ LazyGet(Type toolType) public IToolForm/*?*/ LazyGet(Type toolType)
=> _tools.Find(t => toolType.IsAssignableFrom(t.GetType())); => _tools.Find(toolType.IsInstanceOfType);
internal static readonly IDictionary<Type, (Image/*?*/ Icon, string Name)> IconAndNameCache = new Dictionary<Type, (Image/*?*/ Icon, string Name)> internal static readonly IDictionary<Type, (Image/*?*/ Icon, string Name)> IconAndNameCache = new Dictionary<Type, (Image/*?*/ Icon, string Name)>
{ {