247 lines
7.2 KiB
C#
247 lines
7.2 KiB
C#
using System.Drawing;
|
|
using System.IO;
|
|
using BizHawk.Emulation.Common;
|
|
|
|
namespace BizHawk.Client.Common
|
|
{
|
|
public sealed class EmuClientApi : IEmuClientApi
|
|
{
|
|
private readonly Config _config;
|
|
|
|
private readonly IDialogController _dialogController;
|
|
|
|
private readonly DisplayManagerBase _displayManager;
|
|
|
|
private readonly IMainFormForApi _mainForm;
|
|
|
|
private readonly Action<string> _logCallback;
|
|
|
|
private readonly IEmulator Emulator;
|
|
|
|
private readonly IGameInfo Game;
|
|
|
|
private readonly IVideoProvider VideoProvider;
|
|
|
|
public event BeforeQuickLoadEventHandler BeforeQuickLoad;
|
|
|
|
public event BeforeQuickSaveEventHandler BeforeQuickSave;
|
|
|
|
public event EventHandler RomLoaded;
|
|
|
|
public event StateLoadedEventHandler StateLoaded;
|
|
|
|
public event StateSavedEventHandler StateSaved;
|
|
|
|
public EmuClientApi(
|
|
Config config,
|
|
IDialogController dialogController,
|
|
DisplayManagerBase displayManager,
|
|
IEmulator emulator,
|
|
IGameInfo game,
|
|
IMainFormForApi mainForm,
|
|
Action<string> logCallback)
|
|
{
|
|
_config = config;
|
|
_dialogController = dialogController;
|
|
_displayManager = displayManager;
|
|
Emulator = emulator;
|
|
Game = game;
|
|
_logCallback = logCallback;
|
|
_mainForm = mainForm;
|
|
VideoProvider = Emulator.AsVideoProviderOrDefault();
|
|
|
|
_mainForm.QuicksaveLoad += CallBeforeQuickLoad;
|
|
_mainForm.QuicksaveSave += CallBeforeQuickSave;
|
|
_mainForm.RomLoaded += CallRomLoaded;
|
|
_mainForm.SavestateLoaded += CallStateLoaded;
|
|
_mainForm.SavestateSaved += CallStateSaved;
|
|
}
|
|
|
|
public int BorderHeight() => _displayManager.TransformPoint(new Point(0, 0)).Y;
|
|
|
|
public int BorderWidth() => _displayManager.TransformPoint(new Point(0, 0)).X;
|
|
|
|
public int BufferHeight() => VideoProvider.BufferHeight;
|
|
|
|
public int BufferWidth() => VideoProvider.BufferWidth;
|
|
|
|
#pragma warning disable MA0091 // passing through `sender` is intentional
|
|
private void CallBeforeQuickLoad(object sender, BeforeQuickLoadEventArgs args)
|
|
=> BeforeQuickLoad?.Invoke(sender, args);
|
|
|
|
private void CallBeforeQuickSave(object sender, BeforeQuickSaveEventArgs args)
|
|
=> BeforeQuickSave?.Invoke(sender, args);
|
|
|
|
private void CallRomLoaded(object sender, EventArgs args)
|
|
=> RomLoaded?.Invoke(sender, args);
|
|
|
|
private void CallStateLoaded(object sender, StateLoadedEventArgs args)
|
|
=> StateLoaded?.Invoke(sender, args);
|
|
|
|
private void CallStateSaved(object sender, StateSavedEventArgs args)
|
|
=> StateSaved?.Invoke(sender, args);
|
|
#pragma warning restore MA0091
|
|
|
|
public void ClearAutohold() => _mainForm.ClearHolds();
|
|
|
|
public void CloseEmulator(int? exitCode = null) => _mainForm.CloseEmulator(exitCode);
|
|
|
|
public void CloseRom() => _mainForm.CloseRom();
|
|
|
|
public void DisplayMessages(bool value) => _config.DisplayMessages = value;
|
|
|
|
public void Dispose()
|
|
{
|
|
_mainForm.QuicksaveLoad -= CallBeforeQuickLoad;
|
|
_mainForm.QuicksaveSave -= CallBeforeQuickSave;
|
|
_mainForm.RomLoaded -= CallRomLoaded;
|
|
_mainForm.SavestateLoaded -= CallStateLoaded;
|
|
_mainForm.SavestateSaved -= CallStateSaved;
|
|
}
|
|
|
|
public void DoFrameAdvance()
|
|
{
|
|
_mainForm.FrameAdvance(discardApiHawkSurfaces: false); // we're rendering, so we don't want to discard
|
|
_mainForm.StepRunLoop_Throttle();
|
|
_mainForm.Render();
|
|
}
|
|
|
|
public void DoFrameAdvanceAndUnpause()
|
|
{
|
|
DoFrameAdvance();
|
|
Unpause();
|
|
}
|
|
|
|
public void EnableRewind(bool enabled) => _mainForm.EnableRewind(enabled);
|
|
|
|
public void FrameSkip(int numFrames)
|
|
{
|
|
if (numFrames < 0)
|
|
{
|
|
_logCallback("Invalid frame skip value");
|
|
return;
|
|
}
|
|
|
|
_config.FrameSkip = numFrames;
|
|
_mainForm.FrameSkipMessage();
|
|
}
|
|
|
|
public int GetApproxFramerate() => _mainForm.GetApproxFramerate();
|
|
|
|
public bool GetSoundOn() => _config.SoundEnabled;
|
|
|
|
public int GetTargetScanlineIntensity() => _config.TargetScanlineFilterIntensity;
|
|
|
|
public int GetWindowSize()
|
|
=> _config.GetWindowScaleFor(Emulator.SystemId);
|
|
|
|
public void InvisibleEmulation(bool invisible) => _mainForm.InvisibleEmulation = invisible;
|
|
|
|
public bool IsPaused() => _mainForm.EmulatorPaused;
|
|
|
|
public bool IsSeeking() => _mainForm.IsSeeking;
|
|
|
|
public bool IsTurbo() => _mainForm.IsTurboing;
|
|
|
|
public bool LoadState(string name)
|
|
=> _mainForm.LoadState(
|
|
path: Path.Combine(_config.PathEntries.SaveStateAbsolutePath(Game.System), $"{name}.State"),
|
|
userFriendlyStateName: name,
|
|
suppressOSD: false);
|
|
|
|
public bool OpenRom(string path)
|
|
=> _mainForm.LoadRom(path, new LoadRomArgs(new OpenAdvanced_OpenRom(path)));
|
|
|
|
public void Pause() => _mainForm.PauseEmulator();
|
|
|
|
public void PauseAv() => _mainForm.PauseAvi = true;
|
|
|
|
public void RebootCore() => _mainForm.RebootCore();
|
|
|
|
public void SaveRam() => _mainForm.FlushSaveRAM();
|
|
|
|
// TODO: Change return type to FileWriteResult.
|
|
// We may wish to change more than that, since we have a mostly-dupicate ISaveStateApi.Save, neither has documentation indicating what the differences are.
|
|
public void SaveState(string name)
|
|
{
|
|
FileWriteResult result = _mainForm.SaveState(Path.Combine(_config.PathEntries.SaveStateAbsolutePath(Game.System), $"{name}.State"), name);
|
|
if (result.Exception != null && result.Exception is not UnlessUsingApiException)
|
|
{
|
|
throw result.Exception;
|
|
}
|
|
}
|
|
|
|
public int ScreenHeight() => _displayManager.GetPanelNativeSize().Height;
|
|
|
|
public void Screenshot(string path)
|
|
{
|
|
if (path == null) _mainForm.TakeScreenshot();
|
|
else _mainForm.TakeScreenshot(path);
|
|
}
|
|
|
|
public void ScreenshotToClipboard() => _mainForm.TakeScreenshotToClipboard();
|
|
|
|
public int ScreenWidth() => _displayManager.GetPanelNativeSize().Width;
|
|
|
|
public void SeekFrame(int frame)
|
|
{
|
|
var wasPaused = _mainForm.EmulatorPaused;
|
|
while (Emulator.Frame != frame) _mainForm.SeekFrameAdvance();
|
|
if (!wasPaused) _mainForm.UnpauseEmulator();
|
|
}
|
|
|
|
public void SetClientExtraPadding(int left, int top, int right, int bottom)
|
|
{
|
|
_displayManager.ClientExtraPadding = (left, top, right, bottom);
|
|
_mainForm.FrameBufferResized();
|
|
}
|
|
|
|
public void SetGameExtraPadding(int left, int top, int right, int bottom)
|
|
{
|
|
_displayManager.GameExtraPadding = (left, top, right, bottom);
|
|
_mainForm.FrameBufferResized();
|
|
}
|
|
|
|
public void SetScreenshotOSD(bool value) => _config.ScreenshotCaptureOsd = value;
|
|
|
|
public void SetSoundOn(bool enable)
|
|
{
|
|
if (enable != _config.SoundEnabled) _mainForm.ToggleSound();
|
|
}
|
|
|
|
public void SetTargetScanlineIntensity(int val) => _config.TargetScanlineFilterIntensity = val;
|
|
|
|
public void SetWindowSize(int size)
|
|
{
|
|
if (size == 1 || size == 2 || size == 3 || size == 4 || size == 5 || size == 10)
|
|
{
|
|
_config.SetWindowScaleFor(Emulator.SystemId, size);
|
|
_mainForm.FrameBufferResized(forceWindowResize: true);
|
|
_dialogController.AddOnScreenMessage($"Window size set to {size}x");
|
|
}
|
|
else
|
|
{
|
|
_logCallback("Invalid window size");
|
|
}
|
|
}
|
|
|
|
public void SpeedMode(int percent)
|
|
{
|
|
if (percent is > 0 and <= 6400) _mainForm.ClickSpeedItem(percent);
|
|
else _logCallback("Invalid speed value");
|
|
}
|
|
|
|
public void TogglePause() => _mainForm.TogglePause();
|
|
|
|
public Point TransformPoint(Point point) => _displayManager.TransformPoint(point);
|
|
|
|
public void Unpause() => _mainForm.UnpauseEmulator();
|
|
|
|
public void UnpauseAv() => _mainForm.PauseAvi = false;
|
|
|
|
public int Xpos() => _mainForm.DesktopLocation.X;
|
|
|
|
public int Ypos() => _mainForm.DesktopLocation.Y;
|
|
}
|
|
}
|