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

View File

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

View File

@ -1089,6 +1089,13 @@ namespace BizHawk.Client.EmuHawk
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 OSDManager OSD => DisplayManager.OSD;
@ -1116,6 +1123,8 @@ namespace BizHawk.Client.EmuHawk
public void CreateRewinder()
{
if (ToolControllingRewind is not null) return;
Rewinder?.Dispose();
Rewinder = Emulator.HasSavestates() && Config.Rewind.Enabled && (!Emulator.AsStatable().AvoidRewind || Config.Rewind.AllowSlowStates)
? Config.Rewind.UseDelta
@ -1274,9 +1283,9 @@ namespace BizHawk.Client.EmuHawk
public bool RebootCore()
{
if (IsSlave && Master.WantsToControlReboot)
if (ToolControllingReboot is { } tool)
{
Master.RebootCore();
tool.RebootCore();
return true;
}
else
@ -3257,7 +3266,7 @@ namespace BizHawk.Client.EmuHawk
MovieSession.Movie.SwitchToRecord();
}
if (isRewinding && !IsRewindSlave && MovieSession.Movie.IsRecording())
if (isRewinding && ToolControllingRewind is null && MovieSession.Movie.IsRecording())
{
MovieSession.Movie.Truncate(Emulator.Frame);
}
@ -4175,7 +4184,6 @@ namespace BizHawk.Client.EmuHawk
Emulator.Dispose();
Emulator = new NullEmulator();
Game = GameInfo.NullInstance;
CreateRewinder();
Tools.Restart(Config, Emulator, Game);
RewireSound();
ClearHolds();
@ -4248,25 +4256,6 @@ namespace BizHawk.Client.EmuHawk
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)
{
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
{
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))
{
@ -4311,7 +4300,7 @@ namespace BizHawk.Client.EmuHawk
//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
if (!IsRewindSlave && MovieSession.Movie.IsActive())
if (ToolControllingRewind is null && MovieSession.Movie.IsActive())
{
Rewinder?.Clear();
}
@ -4337,7 +4326,7 @@ namespace BizHawk.Client.EmuHawk
}
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";
if (!File.Exists(path))
@ -4356,9 +4345,9 @@ namespace BizHawk.Client.EmuHawk
return;
}
if (IsSavestateSlave)
if (ToolControllingSavestates is { } tool)
{
Master.SaveState();
tool.SaveState();
return;
}
@ -4409,9 +4398,9 @@ namespace BizHawk.Client.EmuHawk
return;
}
if (IsSavestateSlave)
if (ToolControllingSavestates is { } tool)
{
Master.SaveQuickSave(SlotToInt(quickSlotName));
tool.SaveQuickSave(SlotToInt(quickSlotName));
return;
}
@ -4482,9 +4471,9 @@ namespace BizHawk.Client.EmuHawk
Tools.TAStudio.NamedStatePending = true;
}
if (IsSavestateSlave)
if (ToolControllingSavestates is { } tool)
{
Master.SaveStateAs();
tool.SaveStateAs();
return;
}
@ -4512,7 +4501,7 @@ namespace BizHawk.Client.EmuHawk
private bool LoadStateAs()
{
if (!Emulator.HasSavestates()) return false;
if (IsSavestateSlave) return Master.LoadStateAs();
if (ToolControllingSavestates is { } tool) return tool.LoadStateAs();
var result = this.ShowFileOpenDialog(
discardCWDChange: true,
@ -4525,9 +4514,9 @@ namespace BizHawk.Client.EmuHawk
private void SelectSlot(int slot)
{
if (!Emulator.HasSavestates()) return;
if (IsSavestateSlave)
if (ToolControllingSavestates is { } tool)
{
var handled = Master.SelectSlot(slot);
bool handled = tool.SelectSlot(slot);
if (handled) return;
}
Config.SaveSlot = slot;
@ -4538,9 +4527,9 @@ namespace BizHawk.Client.EmuHawk
private void PreviousSlot()
{
if (!Emulator.HasSavestates()) return;
if (IsSavestateSlave)
if (ToolControllingSavestates is { } tool)
{
var handled = Master.PreviousSlot();
bool handled = tool.PreviousSlot();
if (handled) return;
}
Config.SaveSlot--;
@ -4552,9 +4541,9 @@ namespace BizHawk.Client.EmuHawk
private void NextSlot()
{
if (!Emulator.HasSavestates()) return;
if (IsSavestateSlave)
if (ToolControllingSavestates is { } tool)
{
var handled = Master.NextSlot();
bool handled = tool.NextSlot();
if (handled) return;
}
Config.SaveSlot++;
@ -4565,9 +4554,9 @@ namespace BizHawk.Client.EmuHawk
private void CaptureRewind(bool suppressCaptureRewind)
{
if (IsRewindSlave)
if (ToolControllingRewind is { } tool)
{
Master.CaptureRewind();
tool.CaptureRewind();
}
else if (!suppressCaptureRewind && Rewinder?.Active == true)
{
@ -4581,7 +4570,7 @@ namespace BizHawk.Client.EmuHawk
returnToRecording = false;
if (IsRewindSlave)
if (ToolControllingRewind is { } rewindTool)
{
if (InputManager.ClientControls["Rewind"] || PressRewind)
{
@ -4620,7 +4609,7 @@ namespace BizHawk.Client.EmuHawk
if (isRewinding)
{
runFrame = Emulator.Frame > 1; // TODO: the master should be deciding this!
Master.Rewind();
rewindTool.Rewind();
}
}
else

View File

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

View File

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

View File

@ -473,6 +473,25 @@ namespace BizHawk.Client.EmuHawk
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>
/// 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
@ -482,7 +501,7 @@ namespace BizHawk.Client.EmuHawk
/// you may pass any class or interface
/// </remarks>
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)>
{