Core/Movie: Refactor to class, move to System.

A bit of global state remains (the `header` in `BeginRecordingInput()`) due to unclear lifetime requirements.
This commit is contained in:
Admiral H. Curtiss 2024-01-13 13:14:48 +01:00
parent c76dee7807
commit 95cba6be2b
No known key found for this signature in database
GPG Key ID: F051B4C4044F33FB
32 changed files with 717 additions and 609 deletions

View File

@ -66,11 +66,13 @@ bool BootCore(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
return false; return false;
// Movie settings // Movie settings
if (Movie::IsPlayingInput() && Movie::IsConfigSaved()) auto& system = Core::System::GetInstance();
auto& movie = system.GetMovie();
if (movie.IsPlayingInput() && movie.IsConfigSaved())
{ {
for (ExpansionInterface::Slot slot : ExpansionInterface::MEMCARD_SLOTS) for (ExpansionInterface::Slot slot : ExpansionInterface::MEMCARD_SLOTS)
{ {
if (Movie::IsUsingMemcard(slot) && Movie::IsStartingFromClearSave() && !StartUp.bWii) if (movie.IsUsingMemcard(slot) && movie.IsStartingFromClearSave() && !StartUp.bWii)
{ {
const auto raw_path = const auto raw_path =
File::GetUserPath(D_GCUSER_IDX) + File::GetUserPath(D_GCUSER_IDX) +
@ -142,7 +144,6 @@ bool BootCore(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
if (!boot->riivolution_patches.empty()) if (!boot->riivolution_patches.empty())
Config::SetCurrent(Config::MAIN_FAST_DISC_SPEED, true); Config::SetCurrent(Config::MAIN_FAST_DISC_SPEED, true);
auto& system = Core::System::GetInstance();
system.Initialize(); system.Initialize();
Core::UpdateWantDeterminism(/*initial*/ true); Core::UpdateWantDeterminism(/*initial*/ true);

View File

@ -564,8 +564,8 @@ static void EmuThread(Core::System& system, std::unique_ptr<BootParameters> boot
system.GetCustomAssetLoader().Init(); system.GetCustomAssetLoader().Init();
Common::ScopeGuard asset_loader_guard([&system] { system.GetCustomAssetLoader().Shutdown(); }); Common::ScopeGuard asset_loader_guard([&system] { system.GetCustomAssetLoader().Shutdown(); });
Movie::Init(*boot); system.GetMovie().Init(*boot);
Common::ScopeGuard movie_guard{&Movie::Shutdown}; Common::ScopeGuard movie_guard([&system] { system.GetMovie().Shutdown(); });
AudioCommon::InitSoundStream(system); AudioCommon::InitSoundStream(system);
Common::ScopeGuard audio_guard([&system] { AudioCommon::ShutdownSoundStream(system); }); Common::ScopeGuard audio_guard([&system] { AudioCommon::ShutdownSoundStream(system); });
@ -1019,7 +1019,8 @@ void UpdateWantDeterminism(bool initial)
// For now, this value is not itself configurable. Instead, individual // For now, this value is not itself configurable. Instead, individual
// settings that depend on it, such as GPU determinism mode. should have // settings that depend on it, such as GPU determinism mode. should have
// override options for testing, // override options for testing,
bool new_want_determinism = Movie::IsMovieActive() || NetPlay::IsNetPlayRunning(); auto& system = Core::System::GetInstance();
bool new_want_determinism = system.GetMovie().IsMovieActive() || NetPlay::IsNetPlayRunning();
if (new_want_determinism != s_wants_determinism || initial) if (new_want_determinism != s_wants_determinism || initial)
{ {
NOTICE_LOG_FMT(COMMON, "Want determinism <- {}", new_want_determinism ? "true" : "false"); NOTICE_LOG_FMT(COMMON, "Want determinism <- {}", new_want_determinism ? "true" : "false");
@ -1030,7 +1031,6 @@ void UpdateWantDeterminism(bool initial)
if (ios) if (ios)
ios->UpdateWantDeterminism(new_want_determinism); ios->UpdateWantDeterminism(new_want_determinism);
auto& system = Core::System::GetInstance();
system.GetFifo().UpdateWantDeterminism(new_want_determinism); system.GetFifo().UpdateWantDeterminism(new_want_determinism);
// We need to clear the cache because some parts of the JIT depend on want_determinism, // We need to clear the cache because some parts of the JIT depend on want_determinism,

View File

@ -34,6 +34,7 @@
#include "Core/HW/GCPad.h" #include "Core/HW/GCPad.h"
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/NetPlayProto.h" #include "Core/NetPlayProto.h"
#include "Core/System.h"
#include "InputCommon/GCAdapter.h" #include "InputCommon/GCAdapter.h"
#include "InputCommon/InputConfig.h" #include "InputCommon/InputConfig.h"
#include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoBackendBase.h"
@ -417,7 +418,7 @@ void DolphinAnalytics::MakePerGameBuilder()
// NetPlay / recording. // NetPlay / recording.
builder.AddData("netplay", NetPlay::IsNetPlayRunning()); builder.AddData("netplay", NetPlay::IsNetPlayRunning());
builder.AddData("movie", Movie::IsMovieActive()); builder.AddData("movie", Core::System::GetInstance().GetMovie().IsMovieActive());
// Controller information // Controller information
// We grab enough to tell what percentage of our users are playing with keyboard/mouse, some kind // We grab enough to tell what percentage of our users are playing with keyboard/mouse, some kind

View File

@ -476,7 +476,7 @@ void DVDInterface::ChangeDisc(const std::string& new_path)
m_disc_path_to_insert = new_path; m_disc_path_to_insert = new_path;
m_system.GetCoreTiming().ScheduleEvent(m_system.GetSystemTimers().GetTicksPerSecond(), m_system.GetCoreTiming().ScheduleEvent(m_system.GetSystemTimers().GetTicksPerSecond(),
m_insert_disc); m_insert_disc);
Movie::SignalDiscChange(new_path); m_system.GetMovie().SignalDiscChange(new_path);
for (size_t i = 0; i < m_auto_disc_change_paths.size(); ++i) for (size_t i = 0; i < m_auto_disc_change_paths.size(); ++i)
{ {
@ -1087,7 +1087,7 @@ void DVDInterface::ExecuteCommand(ReplyType reply_type)
const bool force_eject = eject && !kill; const bool force_eject = eject && !kill;
if (Config::Get(Config::MAIN_AUTO_DISC_CHANGE) && !Movie::IsPlayingInput() && if (Config::Get(Config::MAIN_AUTO_DISC_CHANGE) && !m_system.GetMovie().IsPlayingInput() &&
m_system.GetDVDThread().IsInsertedDiscRunning() && !m_auto_disc_change_paths.empty()) m_system.GetDVDThread().IsInsertedDiscRunning() && !m_auto_disc_change_paths.empty())
{ {
m_system.GetCoreTiming().ScheduleEvent( m_system.GetCoreTiming().ScheduleEvent(

View File

@ -36,9 +36,11 @@ ExpansionInterfaceManager::~ExpansionInterfaceManager() = default;
void ExpansionInterfaceManager::AddMemoryCard(Slot slot) void ExpansionInterfaceManager::AddMemoryCard(Slot slot)
{ {
EXIDeviceType memorycard_device; EXIDeviceType memorycard_device;
if (Movie::IsPlayingInput() && Movie::IsConfigSaved())
auto& movie = m_system.GetMovie();
if (movie.IsPlayingInput() && movie.IsConfigSaved())
{ {
if (Movie::IsUsingMemcard(slot)) if (movie.IsUsingMemcard(slot))
{ {
memorycard_device = Config::Get(Config::GetInfoForEXIDevice(slot)); memorycard_device = Config::Get(Config::GetInfoForEXIDevice(slot));
if (memorycard_device != EXIDeviceType::MemoryCardFolder && if (memorycard_device != EXIDeviceType::MemoryCardFolder &&

View File

@ -264,7 +264,7 @@ void CEXIChannel::DoState(PointerWrap& p)
} }
if (type == EXIDeviceType::MemoryCardFolder && old_header_data != m_memcard_header_data && if (type == EXIDeviceType::MemoryCardFolder && old_header_data != m_memcard_header_data &&
!Movie::IsMovieActive()) !m_system.GetMovie().IsMovieActive())
{ {
// We have loaded a savestate that has a GCI folder memcard that is different to the virtual // We have loaded a savestate that has a GCI folder memcard that is different to the virtual
// card that is currently active. In order to prevent the game from recognizing this card as a // card that is currently active. In order to prevent the game from recognizing this card as a

View File

@ -406,9 +406,10 @@ u32 CEXIIPL::GetEmulatedTime(Core::System& system, u32 epoch)
{ {
u64 ltime = 0; u64 ltime = 0;
if (Movie::IsMovieActive()) auto& movie = system.GetMovie();
if (movie.IsMovieActive())
{ {
ltime = Movie::GetRecordingStartTime(); ltime = movie.GetRecordingStartTime();
// let's keep time moving forward, regardless of what it starts at // let's keep time moving forward, regardless of what it starts at
ltime += system.GetCoreTiming().GetTicks() / system.GetSystemTimers().GetTicksPerSecond(); ltime += system.GetCoreTiming().GetTicks() / system.GetSystemTimers().GetTicksPerSecond();

View File

@ -149,7 +149,8 @@ CEXIMemoryCard::CEXIMemoryCard(Core::System& system, const Slot slot, bool gci_f
} }
std::pair<std::string /* path */, bool /* migrate */> std::pair<std::string /* path */, bool /* migrate */>
CEXIMemoryCard::GetGCIFolderPath(Slot card_slot, AllowMovieFolder allow_movie_folder) CEXIMemoryCard::GetGCIFolderPath(Slot card_slot, AllowMovieFolder allow_movie_folder,
Movie::MovieManager& movie)
{ {
std::string path_override = Config::Get(Config::GetInfoForGCIPathOverride(card_slot)); std::string path_override = Config::Get(Config::GetInfoForGCIPathOverride(card_slot));
@ -157,9 +158,8 @@ CEXIMemoryCard::GetGCIFolderPath(Slot card_slot, AllowMovieFolder allow_movie_fo
return {std::move(path_override), false}; return {std::move(path_override), false};
const bool use_movie_folder = allow_movie_folder == AllowMovieFolder::Yes && const bool use_movie_folder = allow_movie_folder == AllowMovieFolder::Yes &&
Movie::IsPlayingInput() && Movie::IsConfigSaved() && movie.IsPlayingInput() && movie.IsConfigSaved() &&
Movie::IsUsingMemcard(card_slot) && movie.IsUsingMemcard(card_slot) && movie.IsStartingFromClearSave();
Movie::IsStartingFromClearSave();
const DiscIO::Region region = Config::ToGameCubeRegion(SConfig::GetInstance().m_region); const DiscIO::Region region = Config::ToGameCubeRegion(SConfig::GetInstance().m_region);
if (use_movie_folder) if (use_movie_folder)
@ -182,7 +182,8 @@ void CEXIMemoryCard::SetupGciFolder(const Memcard::HeaderData& header_data)
current_game_id = Common::swap32(reinterpret_cast<const u8*>(game_id.c_str())); current_game_id = Common::swap32(reinterpret_cast<const u8*>(game_id.c_str()));
} }
const auto [dir_path, migrate] = GetGCIFolderPath(m_card_slot, AllowMovieFolder::Yes); const auto [dir_path, migrate] =
GetGCIFolderPath(m_card_slot, AllowMovieFolder::Yes, m_system.GetMovie());
const File::FileInfo file_info(dir_path); const File::FileInfo file_info(dir_path);
if (!file_info.Exists()) if (!file_info.Exists())
@ -219,8 +220,9 @@ void CEXIMemoryCard::SetupGciFolder(const Memcard::HeaderData& header_data)
void CEXIMemoryCard::SetupRawMemcard(u16 size_mb) void CEXIMemoryCard::SetupRawMemcard(u16 size_mb)
{ {
std::string filename; std::string filename;
if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsUsingMemcard(m_card_slot) && auto& movie = m_system.GetMovie();
Movie::IsStartingFromClearSave()) if (movie.IsPlayingInput() && movie.IsConfigSaved() && movie.IsUsingMemcard(m_card_slot) &&
movie.IsStartingFromClearSave())
{ {
filename = File::GetUserPath(D_GCUSER_IDX) + filename = File::GetUserPath(D_GCUSER_IDX) +
fmt::format("Movie{}.raw", s_card_short_names[m_card_slot]); fmt::format("Movie{}.raw", s_card_short_names[m_card_slot]);
@ -501,7 +503,7 @@ void CEXIMemoryCard::DoState(PointerWrap& p)
// otherwise, we'll assume the user wants to keep their memcards and saves separate, // otherwise, we'll assume the user wants to keep their memcards and saves separate,
// unless we're loading (in which case we let the savestate contents decide, in order to stay // unless we're loading (in which case we let the savestate contents decide, in order to stay
// aligned with them). // aligned with them).
bool storeContents = (Movie::IsMovieActive()); bool storeContents = m_system.GetMovie().IsMovieActive();
p.Do(storeContents); p.Do(storeContents);
if (storeContents) if (storeContents)

View File

@ -26,6 +26,10 @@ namespace Memcard
{ {
struct HeaderData; struct HeaderData;
} }
namespace Movie
{
class MovieManager;
}
namespace ExpansionInterface namespace ExpansionInterface
{ {
@ -58,7 +62,7 @@ public:
static void Shutdown(); static void Shutdown();
static std::pair<std::string /* path */, bool /* migrate */> static std::pair<std::string /* path */, bool /* migrate */>
GetGCIFolderPath(Slot card_slot, AllowMovieFolder allow_movie_folder); GetGCIFolderPath(Slot card_slot, AllowMovieFolder allow_movie_folder, Movie::MovieManager& movie);
private: private:
void SetupGciFolder(const Memcard::HeaderData& header_data); void SetupGciFolder(const Memcard::HeaderData& header_data);

View File

@ -265,19 +265,20 @@ void SerialInterfaceManager::Init()
m_channel[i].in_lo.hex = 0; m_channel[i].in_lo.hex = 0;
m_channel[i].has_recent_device_change = false; m_channel[i].has_recent_device_change = false;
if (Movie::IsMovieActive()) auto& movie = m_system.GetMovie();
if (movie.IsMovieActive())
{ {
m_desired_device_types[i] = SIDEVICE_NONE; m_desired_device_types[i] = SIDEVICE_NONE;
if (Movie::IsUsingGBA(i)) if (movie.IsUsingGBA(i))
{ {
m_desired_device_types[i] = SIDEVICE_GC_GBA_EMULATED; m_desired_device_types[i] = SIDEVICE_GC_GBA_EMULATED;
} }
else if (Movie::IsUsingPad(i)) else if (movie.IsUsingPad(i))
{ {
SIDevices current = Config::Get(Config::GetInfoForSIDevice(i)); SIDevices current = Config::Get(Config::GetInfoForSIDevice(i));
// GC pad-compatible devices can be used for both playing and recording // GC pad-compatible devices can be used for both playing and recording
if (Movie::IsUsingBongo(i)) if (movie.IsUsingBongo(i))
m_desired_device_types[i] = SIDEVICE_GC_TARUKONGA; m_desired_device_types[i] = SIDEVICE_GC_TARUKONGA;
else if (SIDevice_IsGCController(current)) else if (SIDevice_IsGCController(current))
m_desired_device_types[i] = current; m_desired_device_types[i] = current;

View File

@ -125,7 +125,8 @@ bool CSIDevice_GBAEmu::GetData(u32& hi, u32& low)
GCPadStatus pad_status{}; GCPadStatus pad_status{};
if (!NetPlay::IsNetPlayRunning()) if (!NetPlay::IsNetPlayRunning())
pad_status = Pad::GetGBAStatus(m_device_number); pad_status = Pad::GetGBAStatus(m_device_number);
SerialInterface::CSIDevice_GCController::HandleMoviePadStatus(m_device_number, &pad_status); SerialInterface::CSIDevice_GCController::HandleMoviePadStatus(m_system.GetMovie(),
m_device_number, &pad_status);
static constexpr std::array<PadButton, 10> buttons_map = { static constexpr std::array<PadButton, 10> buttons_map = {
PadButton::PAD_BUTTON_A, // A PadButton::PAD_BUTTON_A, // A

View File

@ -11,6 +11,7 @@
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/HW/GCPad.h" #include "Core/HW/GCPad.h"
#include "Core/NetPlayProto.h" #include "Core/NetPlayProto.h"
#include "Core/System.h"
#include "InputCommon/GCAdapter.h" #include "InputCommon/GCAdapter.h"
namespace SerialInterface namespace SerialInterface
@ -38,7 +39,7 @@ GCPadStatus CSIDevice_GCAdapter::GetPadStatus()
pad_status = GCAdapter::Input(m_device_number); pad_status = GCAdapter::Input(m_device_number);
} }
HandleMoviePadStatus(m_device_number, &pad_status); HandleMoviePadStatus(m_system.GetMovie(), m_device_number, &pad_status);
// Our GCAdapter code sets PAD_GET_ORIGIN when a new device has been connected. // Our GCAdapter code sets PAD_GET_ORIGIN when a new device has been connected.
// Watch for this to calibrate real controllers on connection. // Watch for this to calibrate real controllers on connection.

View File

@ -120,25 +120,26 @@ int CSIDevice_GCController::RunBuffer(u8* buffer, int request_length)
return 0; return 0;
} }
void CSIDevice_GCController::HandleMoviePadStatus(int device_number, GCPadStatus* pad_status) void CSIDevice_GCController::HandleMoviePadStatus(Movie::MovieManager& movie, int device_number,
GCPadStatus* pad_status)
{ {
Movie::SetPolledDevice(); movie.SetPolledDevice();
if (NetPlay_GetInput(device_number, pad_status)) if (NetPlay_GetInput(device_number, pad_status))
{ {
} }
else if (Movie::IsPlayingInput()) else if (movie.IsPlayingInput())
{ {
Movie::PlayController(pad_status, device_number); movie.PlayController(pad_status, device_number);
Movie::InputUpdate(); movie.InputUpdate();
} }
else if (Movie::IsRecordingInput()) else if (movie.IsRecordingInput())
{ {
Movie::RecordInput(pad_status, device_number); movie.RecordInput(pad_status, device_number);
Movie::InputUpdate(); movie.InputUpdate();
} }
else else
{ {
Movie::CheckPadStatus(pad_status, device_number); movie.CheckPadStatus(pad_status, device_number);
} }
} }
@ -153,7 +154,7 @@ GCPadStatus CSIDevice_GCController::GetPadStatus()
pad_status = Pad::GetStatus(m_device_number); pad_status = Pad::GetStatus(m_device_number);
} }
HandleMoviePadStatus(m_device_number, &pad_status); HandleMoviePadStatus(m_system.GetMovie(), m_device_number, &pad_status);
// Our GCAdapter code sets PAD_GET_ORIGIN when a new device has been connected. // Our GCAdapter code sets PAD_GET_ORIGIN when a new device has been connected.
// Watch for this to calibrate real controllers on connection. // Watch for this to calibrate real controllers on connection.

View File

@ -9,6 +9,11 @@
#include "Core/HW/SI/SI_Device.h" #include "Core/HW/SI/SI_Device.h"
#include "InputCommon/GCPadStatus.h" #include "InputCommon/GCPadStatus.h"
namespace Movie
{
class MovieManager;
}
namespace SerialInterface namespace SerialInterface
{ {
class CSIDevice_GCController : public ISIDevice class CSIDevice_GCController : public ISIDevice
@ -78,7 +83,8 @@ public:
// Direct rumble to the right GC Controller // Direct rumble to the right GC Controller
static void Rumble(int pad_num, ControlState strength, SIDevices device); static void Rumble(int pad_num, ControlState strength, SIDevices device);
static void HandleMoviePadStatus(int device_number, GCPadStatus* pad_status); static void HandleMoviePadStatus(Movie::MovieManager& movie, int device_number,
GCPadStatus* pad_status);
protected: protected:
void SetOrigin(const GCPadStatus& pad_status); void SetOrigin(const GCPadStatus& pad_status);

View File

@ -852,7 +852,7 @@ void VideoInterfaceManager::Update(u64 ticks)
// in case frame counter display is enabled // in case frame counter display is enabled
if (m_half_line_count == 0 || m_half_line_count == GetHalfLinesPerEvenField()) if (m_half_line_count == 0 || m_half_line_count == GetHalfLinesPerEvenField())
Movie::FrameUpdate(); m_system.GetMovie().FrameUpdate();
// If this half-line is at some boundary of the "active video lines" in either field, we either // If this half-line is at some boundary of the "active video lines" in either field, we either
// need to (a) send a request to the GPU thread to actually render the XFB, or (b) increment // need to (a) send a request to the GPU thread to actually render the XFB, or (b) increment

View File

@ -19,6 +19,7 @@
#include "Core/IOS/USB/Bluetooth/WiimoteDevice.h" #include "Core/IOS/USB/Bluetooth/WiimoteDevice.h"
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/NetPlayClient.h" #include "Core/NetPlayClient.h"
#include "Core/System.h"
#include "Core/WiiUtils.h" #include "Core/WiiUtils.h"
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h" #include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
@ -192,8 +193,9 @@ void Initialize(InitializeMode init_mode)
WiimoteReal::Initialize(init_mode); WiimoteReal::Initialize(init_mode);
// Reload Wiimotes with our settings // Reload Wiimotes with our settings
if (Movie::IsMovieActive()) auto& movie = Core::System::GetInstance().GetMovie();
Movie::ChangeWiiPads(); if (movie.IsMovieActive())
movie.ChangeWiiPads();
} }
void ResetAllWiimotes() void ResetAllWiimotes()

View File

@ -23,6 +23,7 @@
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/HW/Wiimote.h" #include "Core/HW/Wiimote.h"
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/System.h"
#include "Core/HW/WiimoteCommon/WiimoteConstants.h" #include "Core/HW/WiimoteCommon/WiimoteConstants.h"
#include "Core/HW/WiimoteCommon/WiimoteHid.h" #include "Core/HW/WiimoteCommon/WiimoteHid.h"
@ -552,7 +553,8 @@ void Wiimote::Update(const WiimoteEmu::DesiredWiimoteState& target_state)
void Wiimote::SendDataReport(const DesiredWiimoteState& target_state) void Wiimote::SendDataReport(const DesiredWiimoteState& target_state)
{ {
Movie::SetPolledDevice(); auto& movie = Core::System::GetInstance().GetMovie();
movie.SetPolledDevice();
if (InputReportID::ReportDisabled == m_reporting_mode) if (InputReportID::ReportDisabled == m_reporting_mode)
{ {
@ -569,9 +571,8 @@ void Wiimote::SendDataReport(const DesiredWiimoteState& target_state)
DataReportBuilder rpt_builder(m_reporting_mode); DataReportBuilder rpt_builder(m_reporting_mode);
if (Movie::IsPlayingInput() && if (movie.IsPlayingInput() && movie.PlayWiimote(m_bt_device_index, rpt_builder,
Movie::PlayWiimote(m_bt_device_index, rpt_builder, m_active_extension, m_active_extension, GetExtensionEncryptionKey()))
GetExtensionEncryptionKey()))
{ {
// Update buttons in status struct from movie: // Update buttons in status struct from movie:
rpt_builder.GetCoreData(&m_status.buttons); rpt_builder.GetCoreData(&m_status.buttons);
@ -640,8 +641,8 @@ void Wiimote::SendDataReport(const DesiredWiimoteState& target_state)
} }
} }
Movie::CheckWiimoteStatus(m_bt_device_index, rpt_builder, m_active_extension, movie.CheckWiimoteStatus(m_bt_device_index, rpt_builder, m_active_extension,
GetExtensionEncryptionKey()); GetExtensionEncryptionKey());
// Send the report: // Send the report:
InterruptDataInputCallback(rpt_builder.GetDataPtr(), rpt_builder.GetDataSize()); InterruptDataInputCallback(rpt_builder.GetDataPtr(), rpt_builder.GetDataSize());

View File

@ -23,6 +23,7 @@
#include "Core/IOS/ES/ES.h" #include "Core/IOS/ES/ES.h"
#include "Core/IOS/IOS.h" #include "Core/IOS/IOS.h"
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/System.h"
#include "Core/WiiRoot.h" #include "Core/WiiRoot.h"
namespace IOS::HLE::FS namespace IOS::HLE::FS
@ -391,8 +392,9 @@ void HostFileSystem::DoState(PointerWrap& p)
// then a call to p.DoExternal() will be used to skip over reading the contents of the "/" // then a call to p.DoExternal() will be used to skip over reading the contents of the "/"
// directory (it skips over the number of bytes specified by size_of_nand_folder_saved) // directory (it skips over the number of bytes specified by size_of_nand_folder_saved)
auto& movie = Core::System::GetInstance().GetMovie();
bool original_save_state_made_during_movie_recording = bool original_save_state_made_during_movie_recording =
Movie::IsMovieActive() && Core::WiiRootIsTemporary(); movie.IsMovieActive() && Core::WiiRootIsTemporary();
p.Do(original_save_state_made_during_movie_recording); p.Do(original_save_state_made_during_movie_recording);
u32 temp_val = 0; u32 temp_val = 0;
@ -414,17 +416,17 @@ void HostFileSystem::DoState(PointerWrap& p)
else // case where we're in read mode. else // case where we're in read mode.
{ {
DoStateRead(p, "/tmp"); DoStateRead(p, "/tmp");
if (!Movie::IsMovieActive() || !original_save_state_made_during_movie_recording || if (!movie.IsMovieActive() || !original_save_state_made_during_movie_recording ||
!Core::WiiRootIsTemporary() || !Core::WiiRootIsTemporary() ||
(original_save_state_made_during_movie_recording != (original_save_state_made_during_movie_recording !=
(Movie::IsMovieActive() && Core::WiiRootIsTemporary()))) (movie.IsMovieActive() && Core::WiiRootIsTemporary())))
{ {
(void)p.DoExternal(temp_val); (void)p.DoExternal(temp_val);
} }
else else
{ {
p.Do(temp_val); p.Do(temp_val);
if (Movie::IsMovieActive() && Core::WiiRootIsTemporary()) if (movie.IsMovieActive() && Core::WiiRootIsTemporary())
DoStateRead(p, "/"); DoStateRead(p, "/");
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -5,9 +5,11 @@
#include <array> #include <array>
#include <cstring> #include <cstring>
#include <mutex>
#include <optional> #include <optional>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <vector>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
@ -16,6 +18,11 @@ struct BootParameters;
struct GCPadStatus; struct GCPadStatus;
class PointerWrap; class PointerWrap;
namespace Core
{
class System;
}
namespace ExpansionInterface namespace ExpansionInterface
{ {
enum class Slot : int; enum class Slot : int;
@ -137,68 +144,137 @@ static_assert(sizeof(DTMHeader) == 256, "DTMHeader should be 256 bytes");
#pragma pack(pop) #pragma pack(pop)
void FrameUpdate(); enum class PlayMode
void InputUpdate(); {
void Init(const BootParameters& boot); None = 0,
Recording,
Playing,
};
void SetPolledDevice(); class MovieManager
{
public:
explicit MovieManager(Core::System& system);
MovieManager(const MovieManager& other) = delete;
MovieManager(MovieManager&& other) = delete;
MovieManager& operator=(const MovieManager& other) = delete;
MovieManager& operator=(MovieManager&& other) = delete;
~MovieManager();
bool IsRecordingInput(); void FrameUpdate();
bool IsRecordingInputFromSaveState(); void InputUpdate();
bool IsJustStartingRecordingInputFromSaveState(); void Init(const BootParameters& boot);
bool IsJustStartingPlayingInputFromSaveState();
bool IsPlayingInput();
bool IsMovieActive();
bool IsReadOnly();
u64 GetRecordingStartTime();
u64 GetCurrentFrame(); void SetPolledDevice();
u64 GetTotalFrames();
u64 GetCurrentInputCount();
u64 GetTotalInputCount();
u64 GetCurrentLagCount();
u64 GetTotalLagCount();
void SetClearSave(bool enabled); bool IsRecordingInput() const;
void SignalDiscChange(const std::string& new_path); bool IsRecordingInputFromSaveState() const;
void SetReset(bool reset); bool IsJustStartingRecordingInputFromSaveState() const;
bool IsJustStartingPlayingInputFromSaveState() const;
bool IsPlayingInput() const;
bool IsMovieActive() const;
bool IsReadOnly() const;
u64 GetRecordingStartTime() const;
bool IsConfigSaved(); u64 GetCurrentFrame() const;
bool IsStartingFromClearSave(); u64 GetTotalFrames() const;
bool IsUsingMemcard(ExpansionInterface::Slot slot); u64 GetCurrentInputCount() const;
void SetGraphicsConfig(); u64 GetTotalInputCount() const;
bool IsNetPlayRecording(); u64 GetCurrentLagCount() const;
u64 GetTotalLagCount() const;
bool IsUsingPad(int controller); void SetClearSave(bool enabled);
bool IsUsingWiimote(int wiimote); void SignalDiscChange(const std::string& new_path);
bool IsUsingBongo(int controller); void SetReset(bool reset);
bool IsUsingGBA(int controller);
void ChangePads();
void ChangeWiiPads(bool instantly = false);
void SetReadOnly(bool bEnabled); bool IsConfigSaved() const;
bool IsStartingFromClearSave() const;
bool IsUsingMemcard(ExpansionInterface::Slot slot) const;
void SetGraphicsConfig();
bool IsNetPlayRecording() const;
bool BeginRecordingInput(const ControllerTypeArray& controllers, bool IsUsingPad(int controller) const;
const WiimoteEnabledArray& wiimotes); bool IsUsingWiimote(int wiimote) const;
void RecordInput(const GCPadStatus* PadStatus, int controllerID); bool IsUsingBongo(int controller) const;
void RecordWiimote(int wiimote, const u8* data, u8 size); bool IsUsingGBA(int controller) const;
void ChangePads();
void ChangeWiiPads(bool instantly = false);
bool PlayInput(const std::string& movie_path, std::optional<std::string>* savestate_path); void SetReadOnly(bool bEnabled);
void LoadInput(const std::string& movie_path);
void ReadHeader();
void PlayController(GCPadStatus* PadStatus, int controllerID);
bool PlayWiimote(int wiimote, WiimoteCommon::DataReportBuilder& rpt,
WiimoteEmu::ExtensionNumber ext, const WiimoteEmu::EncryptionKey& key);
void EndPlayInput(bool cont);
void SaveRecording(const std::string& filename);
void DoState(PointerWrap& p);
void Shutdown();
void CheckPadStatus(const GCPadStatus* PadStatus, int controllerID);
void CheckWiimoteStatus(int wiimote, const WiimoteCommon::DataReportBuilder& rpt,
WiimoteEmu::ExtensionNumber ext, const WiimoteEmu::EncryptionKey& key);
std::string GetInputDisplay(); bool BeginRecordingInput(const ControllerTypeArray& controllers,
std::string GetRTCDisplay(); const WiimoteEnabledArray& wiimotes);
std::string GetRerecords(); void RecordInput(const GCPadStatus* PadStatus, int controllerID);
void RecordWiimote(int wiimote, const u8* data, u8 size);
bool PlayInput(const std::string& movie_path, std::optional<std::string>* savestate_path);
void LoadInput(const std::string& movie_path);
void ReadHeader();
void PlayController(GCPadStatus* PadStatus, int controllerID);
bool PlayWiimote(int wiimote, WiimoteCommon::DataReportBuilder& rpt,
WiimoteEmu::ExtensionNumber ext, const WiimoteEmu::EncryptionKey& key);
void EndPlayInput(bool cont);
void SaveRecording(const std::string& filename);
void DoState(PointerWrap& p);
void Shutdown();
void CheckPadStatus(const GCPadStatus* PadStatus, int controllerID);
void CheckWiimoteStatus(int wiimote, const WiimoteCommon::DataReportBuilder& rpt,
WiimoteEmu::ExtensionNumber ext, const WiimoteEmu::EncryptionKey& key);
std::string GetInputDisplay();
std::string GetRTCDisplay();
std::string GetRerecords();
private:
void GetSettings();
void CheckInputEnd();
void CheckMD5();
void GetMD5();
bool m_read_only = true;
u32 m_rerecords = 0;
PlayMode m_play_mode = PlayMode::None;
std::array<ControllerType, 4> m_controllers{};
std::array<bool, 4> m_wiimotes{};
ControllerState m_pad_state{};
DTMHeader m_temp_header{};
std::vector<u8> m_temp_input;
u64 m_current_byte = 0;
u64 m_current_frame = 0;
u64 m_total_frames = 0; // VI
u64 m_current_lag_count = 0;
u64 m_total_lag_count = 0;
u64 m_current_input_count = 0;
u64 m_total_input_count = 0;
u64 m_total_tick_count = 0;
u64 m_tick_count_at_last_input = 0;
u64 m_recording_start_time = 0; // seconds since 1970 that recording started
bool m_save_config = false;
bool m_net_play = false;
bool m_clear_save = false;
bool m_has_disc_change = false;
bool m_reset = false;
std::string m_author;
std::string m_disc_change_filename;
std::array<u8, 16> m_md5{};
u8 m_bongos = 0;
u8 m_memcards = 0;
std::array<u8, 20> m_revision{};
u32 m_dsp_irom_hash = 0;
u32 m_dsp_coef_hash = 0;
bool m_recording_from_save_state = false;
bool m_polled = false;
std::string m_current_file_name;
// m_input_display is used by both CPU and GPU (is mutable).
std::mutex m_input_display_lock;
std::array<std::string, 8> m_input_display;
Core::System& m_system;
};
} // namespace Movie } // namespace Movie

View File

@ -1763,8 +1763,9 @@ bool NetPlayClient::StartGame(const std::string& path)
if (m_dialog->IsRecording()) if (m_dialog->IsRecording())
{ {
if (Movie::IsReadOnly()) auto& movie = Core::System::GetInstance().GetMovie();
Movie::SetReadOnly(false); if (movie.IsReadOnly())
movie.SetReadOnly(false);
Movie::ControllerTypeArray controllers{}; Movie::ControllerTypeArray controllers{};
Movie::WiimoteEnabledArray wiimotes{}; Movie::WiimoteEnabledArray wiimotes{};
@ -1778,7 +1779,7 @@ bool NetPlayClient::StartGame(const std::string& path)
controllers[i] = Movie::ControllerType::None; controllers[i] = Movie::ControllerType::None;
wiimotes[i] = m_wiimote_map[i] > 0; wiimotes[i] = m_wiimote_map[i] > 0;
} }
Movie::BeginRecordingInput(controllers, wiimotes); movie.BeginRecordingInput(controllers, wiimotes);
} }
for (unsigned int i = 0; i < 4; ++i) for (unsigned int i = 0; i < 4; ++i)
@ -2114,14 +2115,15 @@ bool NetPlayClient::GetNetPads(const int pad_nb, const bool batching, GCPadStatu
m_pad_buffer[pad_nb].Pop(*pad_status); m_pad_buffer[pad_nb].Pop(*pad_status);
if (Movie::IsRecordingInput()) auto& movie = Core::System::GetInstance().GetMovie();
if (movie.IsRecordingInput())
{ {
Movie::RecordInput(pad_status, pad_nb); movie.RecordInput(pad_status, pad_nb);
Movie::InputUpdate(); movie.InputUpdate();
} }
else else
{ {
Movie::CheckPadStatus(pad_status, pad_nb); movie.CheckPadStatus(pad_status, pad_nb);
} }
return true; return true;

View File

@ -171,7 +171,7 @@ static void DoState(PointerWrap& p)
// Movie must be done before the video backend, because the window is redrawn in the video backend // Movie must be done before the video backend, because the window is redrawn in the video backend
// state load, and the frame number must be up-to-date. // state load, and the frame number must be up-to-date.
Movie::DoState(p); system.GetMovie().DoState(p);
p.DoMarker("Movie"); p.DoMarker("Movie");
// Begin with video backend, so that it gets a chance to clear its caches and writeback modified // Begin with video backend, so that it gets a chance to clear its caches and writeback modified
@ -443,9 +443,10 @@ static void CompressAndDumpState(CompressAndDumpState_args& save_args)
} }
} }
if ((Movie::IsMovieActive()) && !Movie::IsJustStartingRecordingInputFromSaveState()) auto& movie = Core::System::GetInstance().GetMovie();
Movie::SaveRecording(dtmname); if ((movie.IsMovieActive()) && !movie.IsJustStartingRecordingInputFromSaveState())
else if (!Movie::IsMovieActive()) movie.SaveRecording(dtmname);
else if (!movie.IsMovieActive())
File::Delete(dtmname); File::Delete(dtmname);
// Move written state to final location. // Move written state to final location.
@ -867,13 +868,14 @@ void LoadAs(const std::string& filename)
Core::RunOnCPUThread( Core::RunOnCPUThread(
[&] { [&] {
// Save temp buffer for undo load state // Save temp buffer for undo load state
if (!Movie::IsJustStartingRecordingInputFromSaveState()) auto& movie = Core::System::GetInstance().GetMovie();
if (!movie.IsJustStartingRecordingInputFromSaveState())
{ {
std::lock_guard lk2(s_undo_load_buffer_mutex); std::lock_guard lk2(s_undo_load_buffer_mutex);
SaveToBuffer(s_undo_load_buffer); SaveToBuffer(s_undo_load_buffer);
const std::string dtmpath = File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"; const std::string dtmpath = File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm";
if (Movie::IsMovieActive()) if (movie.IsMovieActive())
Movie::SaveRecording(dtmpath); movie.SaveRecording(dtmpath);
else if (File::Exists(dtmpath)) else if (File::Exists(dtmpath))
File::Delete(dtmpath); File::Delete(dtmpath);
} }
@ -904,10 +906,10 @@ void LoadAs(const std::string& filename)
Core::DisplayMessage( Core::DisplayMessage(
fmt::format("Loaded State from {}", tempfilename.filename().string()), 2000); fmt::format("Loaded State from {}", tempfilename.filename().string()), 2000);
if (File::Exists(filename + ".dtm")) if (File::Exists(filename + ".dtm"))
Movie::LoadInput(filename + ".dtm"); movie.LoadInput(filename + ".dtm");
else if (!Movie::IsJustStartingRecordingInputFromSaveState() && else if (!movie.IsJustStartingRecordingInputFromSaveState() &&
!Movie::IsJustStartingPlayingInputFromSaveState()) !movie.IsJustStartingPlayingInputFromSaveState())
Movie::EndPlayInput(false); movie.EndPlayInput(false);
} }
else else
{ {
@ -1015,13 +1017,14 @@ void UndoLoadState()
std::lock_guard lk(s_undo_load_buffer_mutex); std::lock_guard lk(s_undo_load_buffer_mutex);
if (!s_undo_load_buffer.empty()) if (!s_undo_load_buffer.empty())
{ {
if (Movie::IsMovieActive()) auto& movie = Core::System::GetInstance().GetMovie();
if (movie.IsMovieActive())
{ {
const std::string dtmpath = File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"; const std::string dtmpath = File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm";
if (File::Exists(dtmpath)) if (File::Exists(dtmpath))
{ {
LoadFromBuffer(s_undo_load_buffer); LoadFromBuffer(s_undo_load_buffer);
Movie::LoadInput(dtmpath); movie.LoadInput(dtmpath);
} }
else else
{ {

View File

@ -26,6 +26,7 @@
#include "Core/HW/SystemTimers.h" #include "Core/HW/SystemTimers.h"
#include "Core/HW/VideoInterface.h" #include "Core/HW/VideoInterface.h"
#include "Core/HW/WII_IPC.h" #include "Core/HW/WII_IPC.h"
#include "Core/Movie.h"
#include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
@ -52,7 +53,7 @@ struct System::Impl
m_mmu(system, m_memory, m_power_pc), m_processor_interface(system), m_mmu(system, m_memory, m_power_pc), m_processor_interface(system),
m_serial_interface(system), m_system_timers(system), m_video_interface(system), m_serial_interface(system), m_system_timers(system), m_video_interface(system),
m_interpreter(system, m_power_pc.GetPPCState(), m_mmu), m_jit_interface(system), m_interpreter(system, m_power_pc.GetPPCState(), m_mmu), m_jit_interface(system),
m_fifo_player(system), m_fifo_recorder(system) m_fifo_player(system), m_fifo_recorder(system), m_movie(system)
{ {
} }
@ -93,6 +94,7 @@ struct System::Impl
VideoCommon::CustomAssetLoader m_custom_asset_loader; VideoCommon::CustomAssetLoader m_custom_asset_loader;
FifoPlayer m_fifo_player; FifoPlayer m_fifo_player;
FifoRecorder m_fifo_recorder; FifoRecorder m_fifo_recorder;
Movie::MovieManager m_movie;
}; };
System::System() : m_impl{std::make_unique<Impl>(*this)} System::System() : m_impl{std::make_unique<Impl>(*this)}
@ -248,6 +250,11 @@ PowerPC::MMU& System::GetMMU() const
return m_impl->m_mmu; return m_impl->m_mmu;
} }
Movie::MovieManager& System::GetMovie() const
{
return m_impl->m_movie;
}
PixelEngine::PixelEngineManager& System::GetPixelEngine() const PixelEngine::PixelEngineManager& System::GetPixelEngine() const
{ {
return m_impl->m_pixel_engine; return m_impl->m_pixel_engine;

View File

@ -74,6 +74,10 @@ namespace MemoryInterface
{ {
class MemoryInterfaceManager; class MemoryInterfaceManager;
}; };
namespace Movie
{
class MovieManager;
}
namespace PixelEngine namespace PixelEngine
{ {
class PixelEngineManager; class PixelEngineManager;
@ -161,6 +165,7 @@ public:
Memory::MemoryManager& GetMemory() const; Memory::MemoryManager& GetMemory() const;
MemoryInterface::MemoryInterfaceManager& GetMemoryInterface() const; MemoryInterface::MemoryInterfaceManager& GetMemoryInterface() const;
PowerPC::MMU& GetMMU() const; PowerPC::MMU& GetMMU() const;
Movie::MovieManager& GetMovie() const;
PixelEngine::PixelEngineManager& GetPixelEngine() const; PixelEngine::PixelEngineManager& GetPixelEngine() const;
PixelShaderManager& GetPixelShaderManager() const; PixelShaderManager& GetPixelShaderManager() const;
PowerPC::PowerPCManager& GetPowerPC() const; PowerPC::PowerPCManager& GetPowerPC() const;

View File

@ -28,6 +28,7 @@
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/NetPlayClient.h" #include "Core/NetPlayClient.h"
#include "Core/SysConf.h" #include "Core/SysConf.h"
#include "Core/System.h"
namespace Core namespace Core
{ {
@ -127,24 +128,25 @@ static bool CopyNandFile(FS::FileSystem* source_fs, const std::string& source_fi
static void InitializeDeterministicWiiSaves(FS::FileSystem* session_fs, static void InitializeDeterministicWiiSaves(FS::FileSystem* session_fs,
const BootSessionData& boot_session_data) const BootSessionData& boot_session_data)
{ {
auto& movie = Core::System::GetInstance().GetMovie();
const u64 title_id = SConfig::GetInstance().GetTitleID(); const u64 title_id = SConfig::GetInstance().GetTitleID();
const auto configured_fs = FS::MakeFileSystem(FS::Location::Configured); const auto configured_fs = FS::MakeFileSystem(FS::Location::Configured);
if (Movie::IsRecordingInput()) if (movie.IsRecordingInput())
{ {
if (NetPlay::IsNetPlayRunning() && !SConfig::GetInstance().bCopyWiiSaveNetplay) if (NetPlay::IsNetPlayRunning() && !SConfig::GetInstance().bCopyWiiSaveNetplay)
{ {
Movie::SetClearSave(true); movie.SetClearSave(true);
} }
else else
{ {
// TODO: Check for the actual save data // TODO: Check for the actual save data
const std::string path = Common::GetTitleDataPath(title_id) + "/banner.bin"; const std::string path = Common::GetTitleDataPath(title_id) + "/banner.bin";
Movie::SetClearSave(!configured_fs->GetMetadata(IOS::PID_KERNEL, IOS::PID_KERNEL, path)); movie.SetClearSave(!configured_fs->GetMetadata(IOS::PID_KERNEL, IOS::PID_KERNEL, path));
} }
} }
if ((NetPlay::IsNetPlayRunning() && SConfig::GetInstance().bCopyWiiSaveNetplay) || if ((NetPlay::IsNetPlayRunning() && SConfig::GetInstance().bCopyWiiSaveNetplay) ||
(Movie::IsMovieActive() && !Movie::IsStartingFromClearSave())) (movie.IsMovieActive() && !movie.IsStartingFromClearSave()))
{ {
auto* sync_fs = boot_session_data.GetWiiSyncFS(); auto* sync_fs = boot_session_data.GetWiiSyncFS();
auto& sync_titles = boot_session_data.GetWiiSyncTitles(); auto& sync_titles = boot_session_data.GetWiiSyncTitles();
@ -154,7 +156,7 @@ static void InitializeDeterministicWiiSaves(FS::FileSystem* session_fs,
sync_fs ? "sync_fs" : "configured_fs"); sync_fs ? "sync_fs" : "configured_fs");
// Copy the current user's save to the Blank NAND // Copy the current user's save to the Blank NAND
if (Movie::IsMovieActive() && !NetPlay::IsNetPlayRunning()) if (movie.IsMovieActive() && !NetPlay::IsNetPlayRunning())
{ {
INFO_LOG_FMT(CORE, "Wii Save Init: Copying {0:016x}.", title_id); INFO_LOG_FMT(CORE, "Wii Save Init: Copying {0:016x}.", title_id);
CopySave(source_fs, session_fs, title_id); CopySave(source_fs, session_fs, title_id);

View File

@ -15,6 +15,7 @@
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/System.h"
#include "DolphinQt/Config/ControllerInterface/ControllerInterfaceWindow.h" #include "DolphinQt/Config/ControllerInterface/ControllerInterfaceWindow.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h" #include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h"
@ -197,9 +198,9 @@ void AchievementSettingsWidget::LoadSettings()
SignalBlocking(m_common_hardcore_enabled_input) SignalBlocking(m_common_hardcore_enabled_input)
->setChecked(Config::Get(Config::RA_HARDCORE_ENABLED)); ->setChecked(Config::Get(Config::RA_HARDCORE_ENABLED));
SignalBlocking(m_common_hardcore_enabled_input) SignalBlocking(m_common_hardcore_enabled_input)
->setEnabled(enabled && ->setEnabled(enabled && (hardcore_enabled ||
(hardcore_enabled || (Core::GetState() == Core::State::Uninitialized &&
(Core::GetState() == Core::State::Uninitialized && !Movie::IsPlayingInput()))); !Core::System::GetInstance().GetMovie().IsPlayingInput())));
SignalBlocking(m_common_progress_enabled_input) SignalBlocking(m_common_progress_enabled_input)
->setChecked(Config::Get(Config::RA_PROGRESS_ENABLED)); ->setChecked(Config::Get(Config::RA_PROGRESS_ENABLED));

View File

@ -365,7 +365,7 @@ void GBAWidget::SaveSettings()
bool GBAWidget::CanControlCore() bool GBAWidget::CanControlCore()
{ {
return !Movie::IsMovieActive() && !NetPlay::IsNetPlayRunning(); return !Core::System::GetInstance().GetMovie().IsMovieActive() && !NetPlay::IsNetPlayRunning();
} }
bool GBAWidget::CanResetCore() bool GBAWidget::CanResetCore()

View File

@ -277,7 +277,7 @@ MainWindow::MainWindow(std::unique_ptr<BootParameters> boot_parameters,
if (!movie_path.empty()) if (!movie_path.empty())
{ {
std::optional<std::string> savestate_path; std::optional<std::string> savestate_path;
if (Movie::PlayInput(movie_path, &savestate_path)) if (Core::System::GetInstance().GetMovie().PlayInput(movie_path, &savestate_path))
{ {
m_pending_boot->boot_session_data.SetSavestateData(std::move(savestate_path), m_pending_boot->boot_session_data.SetSavestateData(std::move(savestate_path),
DeleteSavestateAfterBoot::No); DeleteSavestateAfterBoot::No);
@ -646,8 +646,9 @@ void MainWindow::ConnectHotkeys()
connect(m_hotkey_scheduler, &HotkeyScheduler::ConnectWiiRemote, this, connect(m_hotkey_scheduler, &HotkeyScheduler::ConnectWiiRemote, this,
&MainWindow::OnConnectWiiRemote); &MainWindow::OnConnectWiiRemote);
connect(m_hotkey_scheduler, &HotkeyScheduler::ToggleReadOnlyMode, [this] { connect(m_hotkey_scheduler, &HotkeyScheduler::ToggleReadOnlyMode, [this] {
bool read_only = !Movie::IsReadOnly(); auto& movie = Core::System::GetInstance().GetMovie();
Movie::SetReadOnly(read_only); bool read_only = !movie.IsReadOnly();
movie.SetReadOnly(read_only);
emit ReadOnlyModeChanged(read_only); emit ReadOnlyModeChanged(read_only);
}); });
@ -1011,9 +1012,10 @@ void MainWindow::ForceStop()
void MainWindow::Reset() void MainWindow::Reset()
{ {
if (Movie::IsRecordingInput())
Movie::SetReset(true);
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& movie = system.GetMovie();
if (movie.IsRecordingInput())
movie.SetReset(true);
system.GetProcessorInterface().ResetButton_Tap(); system.GetProcessorInterface().ResetButton_Tap();
} }
@ -1853,15 +1855,16 @@ void MainWindow::OnPlayRecording()
if (dtm_file.isEmpty()) if (dtm_file.isEmpty())
return; return;
if (!Movie::IsReadOnly()) auto& movie = Core::System::GetInstance().GetMovie();
if (!movie.IsReadOnly())
{ {
// let's make the read-only flag consistent at the start of a movie. // let's make the read-only flag consistent at the start of a movie.
Movie::SetReadOnly(true); movie.SetReadOnly(true);
emit ReadOnlyModeChanged(true); emit ReadOnlyModeChanged(true);
} }
std::optional<std::string> savestate_path; std::optional<std::string> savestate_path;
if (Movie::PlayInput(dtm_file.toStdString(), &savestate_path)) if (movie.PlayInput(dtm_file.toStdString(), &savestate_path))
{ {
emit RecordingStatusChanged(true); emit RecordingStatusChanged(true);
@ -1871,14 +1874,17 @@ void MainWindow::OnPlayRecording()
void MainWindow::OnStartRecording() void MainWindow::OnStartRecording()
{ {
if ((!Core::IsRunningAndStarted() && Core::IsRunning()) || Movie::IsRecordingInput() || auto& movie = Core::System::GetInstance().GetMovie();
Movie::IsPlayingInput()) if ((!Core::IsRunningAndStarted() && Core::IsRunning()) || movie.IsRecordingInput() ||
movie.IsPlayingInput())
{
return; return;
}
if (Movie::IsReadOnly()) if (movie.IsReadOnly())
{ {
// The user just chose to record a movie, so that should take precedence // The user just chose to record a movie, so that should take precedence
Movie::SetReadOnly(false); movie.SetReadOnly(false);
emit ReadOnlyModeChanged(true); emit ReadOnlyModeChanged(true);
} }
@ -1897,7 +1903,7 @@ void MainWindow::OnStartRecording()
wiimotes[i] = Config::Get(Config::GetInfoForWiimoteSource(i)) != WiimoteSource::None; wiimotes[i] = Config::Get(Config::GetInfoForWiimoteSource(i)) != WiimoteSource::None;
} }
if (Movie::BeginRecordingInput(controllers, wiimotes)) if (movie.BeginRecordingInput(controllers, wiimotes))
{ {
emit RecordingStatusChanged(true); emit RecordingStatusChanged(true);
@ -1908,10 +1914,11 @@ void MainWindow::OnStartRecording()
void MainWindow::OnStopRecording() void MainWindow::OnStopRecording()
{ {
if (Movie::IsRecordingInput()) auto& movie = Core::System::GetInstance().GetMovie();
if (movie.IsRecordingInput())
OnExportRecording(); OnExportRecording();
if (Movie::IsMovieActive()) if (movie.IsMovieActive())
Movie::EndPlayInput(false); movie.EndPlayInput(false);
emit RecordingStatusChanged(false); emit RecordingStatusChanged(false);
} }
@ -1921,7 +1928,7 @@ void MainWindow::OnExportRecording()
QString dtm_file = DolphinFileDialog::getSaveFileName( QString dtm_file = DolphinFileDialog::getSaveFileName(
this, tr("Save Recording File As"), QString(), tr("Dolphin TAS Movies (*.dtm)")); this, tr("Save Recording File As"), QString(), tr("Dolphin TAS Movies (*.dtm)"));
if (!dtm_file.isEmpty()) if (!dtm_file.isEmpty())
Movie::SaveRecording(dtm_file.toStdString()); Core::System::GetInstance().GetMovie().SaveRecording(dtm_file.toStdString());
}); });
} }

View File

@ -146,7 +146,8 @@ void MenuBar::OnEmulationStateChanged(Core::State state)
#else // USE_RETRO_ACHIEVEMENTS #else // USE_RETRO_ACHIEVEMENTS
m_recording_play->setEnabled(m_game_selected && !running); m_recording_play->setEnabled(m_game_selected && !running);
#endif // USE_RETRO_ACHIEVEMENTS #endif // USE_RETRO_ACHIEVEMENTS
m_recording_start->setEnabled((m_game_selected || running) && !Movie::IsPlayingInput()); m_recording_start->setEnabled((m_game_selected || running) &&
!Core::System::GetInstance().GetMovie().IsPlayingInput());
// JIT // JIT
m_jit_interpreter_core->setEnabled(running); m_jit_interpreter_core->setEnabled(running);
@ -775,8 +776,9 @@ void MenuBar::AddMovieMenu()
m_recording_read_only = movie_menu->addAction(tr("&Read-Only Mode")); m_recording_read_only = movie_menu->addAction(tr("&Read-Only Mode"));
m_recording_read_only->setCheckable(true); m_recording_read_only->setCheckable(true);
m_recording_read_only->setChecked(Movie::IsReadOnly()); m_recording_read_only->setChecked(Core::System::GetInstance().GetMovie().IsReadOnly());
connect(m_recording_read_only, &QAction::toggled, [](bool value) { Movie::SetReadOnly(value); }); connect(m_recording_read_only, &QAction::toggled,
[](bool value) { Core::System::GetInstance().GetMovie().SetReadOnly(value); });
movie_menu->addAction(tr("TAS Input"), this, [this] { emit ShowTASInput(); }); movie_menu->addAction(tr("TAS Input"), this, [this] { emit ShowTASInput(); });
@ -1231,7 +1233,8 @@ void MenuBar::OnSelectionChanged(std::shared_ptr<const UICommon::GameFile> game_
m_game_selected = !!game_file; m_game_selected = !!game_file;
m_recording_play->setEnabled(m_game_selected && !Core::IsRunning()); m_recording_play->setEnabled(m_game_selected && !Core::IsRunning());
m_recording_start->setEnabled((m_game_selected || Core::IsRunning()) && !Movie::IsPlayingInput()); m_recording_start->setEnabled((m_game_selected || Core::IsRunning()) &&
!Core::System::GetInstance().GetMovie().IsPlayingInput());
} }
void MenuBar::OnRecordingStatusChanged(bool recording) void MenuBar::OnRecordingStatusChanged(bool recording)

View File

@ -6,6 +6,7 @@
#include <QMouseEvent> #include <QMouseEvent>
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/System.h"
#include "DolphinQt/QtUtils/QueueOnObject.h" #include "DolphinQt/QtUtils/QueueOnObject.h"
#include "DolphinQt/TAS/TASInputWindow.h" #include "DolphinQt/TAS/TASInputWindow.h"
@ -23,7 +24,8 @@ bool TASCheckBox::GetValue() const
if (check_state == Qt::PartiallyChecked) if (check_state == Qt::PartiallyChecked)
{ {
const u64 frames_elapsed = Movie::GetCurrentFrame() - m_frame_turbo_started; const u64 frames_elapsed =
Core::System::GetInstance().GetMovie().GetCurrentFrame() - m_frame_turbo_started;
return static_cast<int>(frames_elapsed % m_turbo_total_frames) < m_turbo_press_frames; return static_cast<int>(frames_elapsed % m_turbo_total_frames) < m_turbo_press_frames;
} }
@ -50,7 +52,7 @@ void TASCheckBox::mousePressEvent(QMouseEvent* event)
return; return;
} }
m_frame_turbo_started = Movie::GetCurrentFrame(); m_frame_turbo_started = Core::System::GetInstance().GetMovie().GetCurrentFrame();
m_turbo_press_frames = m_parent->GetTurboPressFrames(); m_turbo_press_frames = m_parent->GetTurboPressFrames();
m_turbo_total_frames = m_turbo_press_frames + m_parent->GetTurboReleaseFrames(); m_turbo_total_frames = m_turbo_press_frames + m_parent->GetTurboReleaseFrames();
setCheckState(Qt::PartiallyChecked); setCheckState(Qt::PartiallyChecked);

View File

@ -11,6 +11,7 @@
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/Config/NetplaySettings.h" #include "Core/Config/NetplaySettings.h"
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/System.h"
#include "VideoCommon/AbstractGfx.h" #include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/AbstractPipeline.h" #include "VideoCommon/AbstractPipeline.h"
@ -284,26 +285,27 @@ void OnScreenUI::DrawDebugText()
ImGui::GetIO().DisplaySize); ImGui::GetIO().DisplaySize);
if (ImGui::Begin("Movie", nullptr, ImGuiWindowFlags_NoFocusOnAppearing)) if (ImGui::Begin("Movie", nullptr, ImGuiWindowFlags_NoFocusOnAppearing))
{ {
if (Movie::IsPlayingInput()) auto& movie = Core::System::GetInstance().GetMovie();
if (movie.IsPlayingInput())
{ {
ImGui::Text("Frame: %" PRIu64 " / %" PRIu64, Movie::GetCurrentFrame(), ImGui::Text("Frame: %" PRIu64 " / %" PRIu64, movie.GetCurrentFrame(),
Movie::GetTotalFrames()); movie.GetTotalFrames());
ImGui::Text("Input: %" PRIu64 " / %" PRIu64, Movie::GetCurrentInputCount(), ImGui::Text("Input: %" PRIu64 " / %" PRIu64, movie.GetCurrentInputCount(),
Movie::GetTotalInputCount()); movie.GetTotalInputCount());
} }
else if (Config::Get(Config::MAIN_SHOW_FRAME_COUNT)) else if (Config::Get(Config::MAIN_SHOW_FRAME_COUNT))
{ {
ImGui::Text("Frame: %" PRIu64, Movie::GetCurrentFrame()); ImGui::Text("Frame: %" PRIu64, movie.GetCurrentFrame());
ImGui::Text("Input: %" PRIu64, Movie::GetCurrentInputCount()); ImGui::Text("Input: %" PRIu64, movie.GetCurrentInputCount());
} }
if (Config::Get(Config::MAIN_SHOW_LAG)) if (Config::Get(Config::MAIN_SHOW_LAG))
ImGui::Text("Lag: %" PRIu64 "\n", Movie::GetCurrentLagCount()); ImGui::Text("Lag: %" PRIu64 "\n", movie.GetCurrentLagCount());
if (Config::Get(Config::MAIN_MOVIE_SHOW_INPUT_DISPLAY)) if (Config::Get(Config::MAIN_MOVIE_SHOW_INPUT_DISPLAY))
ImGui::TextUnformatted(Movie::GetInputDisplay().c_str()); ImGui::TextUnformatted(movie.GetInputDisplay().c_str());
if (Config::Get(Config::MAIN_MOVIE_SHOW_RTC)) if (Config::Get(Config::MAIN_MOVIE_SHOW_RTC))
ImGui::TextUnformatted(Movie::GetRTCDisplay().c_str()); ImGui::TextUnformatted(movie.GetRTCDisplay().c_str());
if (Config::Get(Config::MAIN_MOVIE_SHOW_RERECORD)) if (Config::Get(Config::MAIN_MOVIE_SHOW_RERECORD))
ImGui::TextUnformatted(Movie::GetRerecords().c_str()); ImGui::TextUnformatted(movie.GetRerecords().c_str());
} }
ImGui::End(); ImGui::End();
} }

View File

@ -47,8 +47,9 @@ static bool IsVSyncActive(bool enabled)
void UpdateActiveConfig() void UpdateActiveConfig()
{ {
if (Movie::IsPlayingInput() && Movie::IsConfigSaved()) auto& movie = Core::System::GetInstance().GetMovie();
Movie::SetGraphicsConfig(); if (movie.IsPlayingInput() && movie.IsConfigSaved())
movie.SetGraphicsConfig();
g_ActiveConfig = g_Config; g_ActiveConfig = g_Config;
g_ActiveConfig.bVSyncActive = IsVSyncActive(g_ActiveConfig.bVSync); g_ActiveConfig.bVSyncActive = IsVSyncActive(g_ActiveConfig.bVSync);
} }