diff --git a/Source/Core/Core/HW/SI/SI.cpp b/Source/Core/Core/HW/SI/SI.cpp index caaa95cbae..a45185527a 100644 --- a/Source/Core/Core/HW/SI/SI.cpp +++ b/Source/Core/Core/HW/SI/SI.cpp @@ -419,7 +419,11 @@ void Init() { s_desired_device_types[i] = SIDEVICE_NONE; - if (Movie::IsUsingPad(i)) + if (Movie::IsUsingGBA(i)) + { + s_desired_device_types[i] = SIDEVICE_GC_GBA_EMULATED; + } + else if (Movie::IsUsingPad(i)) { SIDevices current = SConfig::GetInstance().m_SIDevice[i]; // GC pad-compatible devices can be used for both playing and recording diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index 7ea8c0a56e..31e8ca3b43 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -82,7 +82,8 @@ static bool s_bReadOnly = true; static u32 s_rerecords = 0; static PlayMode s_playMode = MODE_NONE; -static u8 s_controllers = 0; +static std::array s_controllers{}; +static std::array s_wiimotes{}; static ControllerState s_padState; static DTMHeader tmpHeader; static std::vector s_temp_input; @@ -157,24 +158,33 @@ std::string GetInputDisplay() { if (!IsMovieActive()) { - s_controllers = 0; + s_controllers = {}; + s_wiimotes = {}; for (int i = 0; i < 4; ++i) { - if (SerialInterface::GetDeviceType(i) != SerialInterface::SIDEVICE_NONE) - s_controllers |= (1 << i); - if (WiimoteCommon::GetSource(i) != WiimoteSource::None) - s_controllers |= (1 << (i + 4)); + if (SerialInterface::GetDeviceType(i) == SerialInterface::SIDEVICE_GC_GBA_EMULATED) + s_controllers[i] = ControllerType::GBA; + else if (SerialInterface::GetDeviceType(i) != SerialInterface::SIDEVICE_NONE) + s_controllers[i] = ControllerType::GC; + else + s_controllers[i] = ControllerType::None; + s_wiimotes[i] = WiimoteCommon::GetSource(i) != WiimoteSource::None; } } std::string input_display; { std::lock_guard guard(s_input_display_lock); - for (int i = 0; i < 8; ++i) + for (int i = 0; i < 4; ++i) { - if ((s_controllers & (1 << i)) != 0) + if (IsUsingPad(i)) input_display += s_InputDisplay[i] + '\n'; } + for (int i = 0; i < 4; ++i) + { + if (IsUsingWiimote(i)) + input_display += s_InputDisplay[i + 4] + '\n'; + } } return input_display; } @@ -386,7 +396,7 @@ void SetReset(bool reset) bool IsUsingPad(int controller) { - return ((s_controllers & (1 << controller)) != 0); + return s_controllers[controller] != ControllerType::None; } bool IsUsingBongo(int controller) @@ -394,9 +404,14 @@ bool IsUsingBongo(int controller) return ((s_bongos & (1 << controller)) != 0); } +bool IsUsingGBA(int controller) +{ + return s_controllers[controller] == ControllerType::GBA; +} + bool IsUsingWiimote(int wiimote) { - return ((s_controllers & (1 << (wiimote + 4))) != 0); + return s_wiimotes[wiimote]; } bool IsConfigSaved() @@ -425,21 +440,29 @@ void ChangePads() if (!Core::IsRunning()) return; - int controllers = 0; + ControllerTypeArray controllers{}; for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i) { - if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i])) - controllers |= (1 << i); + if (SConfig::GetInstance().m_SIDevice[i] == SerialInterface::SIDEVICE_GC_GBA_EMULATED) + controllers[i] = ControllerType::GBA; + else if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i])) + controllers[i] = ControllerType::GC; + else + controllers[i] = ControllerType::None; } - if ((s_controllers & 0x0F) == controllers) + if (s_controllers == controllers) return; for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i) { SerialInterface::SIDevices device = SerialInterface::SIDEVICE_NONE; - if (IsUsingPad(i)) + if (IsUsingGBA(i)) + { + device = SerialInterface::SIDEVICE_GC_GBA_EMULATED; + } + else if (IsUsingPad(i)) { if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i])) { @@ -459,14 +482,15 @@ void ChangePads() // NOTE: Host / Emu Threads void ChangeWiiPads(bool instantly) { - int controllers = 0; + WiimoteEnabledArray wiimotes{}; for (int i = 0; i < MAX_WIIMOTES; ++i) - if (WiimoteCommon::GetSource(i) != WiimoteSource::None) - controllers |= (1 << i); + { + wiimotes[i] = WiimoteCommon::GetSource(i) != WiimoteSource::None; + } // This is important for Wiimotes, because they can desync easily if they get re-activated - if (instantly && (s_controllers >> 4) == controllers) + if (instantly && s_wiimotes == wiimotes) return; const auto bt = WiiUtils::GetBluetoothEmuDevice(); @@ -481,13 +505,16 @@ void ChangeWiiPads(bool instantly) } // NOTE: Host Thread -bool BeginRecordingInput(int controllers) +bool BeginRecordingInput(const ControllerTypeArray& controllers, + const WiimoteEnabledArray& wiimotes) { - if (s_playMode != MODE_NONE || controllers == 0) + if (s_playMode != MODE_NONE || + (controllers == ControllerTypeArray{} && wiimotes == WiimoteEnabledArray{})) return false; - Core::RunAsCPUThread([controllers] { + Core::RunAsCPUThread([controllers, wiimotes] { s_controllers = controllers; + s_wiimotes = wiimotes; s_currentFrame = s_totalFrames = 0; s_currentLagCount = s_totalLagCount = 0; s_currentInputCount = s_totalInputCount = 0; @@ -842,7 +869,16 @@ void RecordWiimote(int wiimote, const u8* data, u8 size) // NOTE: EmuThread / Host Thread void ReadHeader() { - s_controllers = tmpHeader.controllers; + for (int i = 0; i < 4; ++i) + { + if (tmpHeader.GBAControllers & (1 << i)) + s_controllers[i] = ControllerType::GBA; + else if (tmpHeader.controllers & (1 << i)) + s_controllers[i] = ControllerType::GC; + else + s_controllers[i] = ControllerType::None; + s_wiimotes[i] = (tmpHeader.controllers & (1 << (i + 4))) != 0; + } s_recordingStartTime = tmpHeader.recordingStartTime; if (s_rerecords < tmpHeader.numRerecords) s_rerecords = tmpHeader.numRerecords; @@ -1219,9 +1255,10 @@ bool PlayWiimote(int wiimote, WiimoteCommon::DataReportBuilder& rpt, int ext, PanicAlertFmtT( "Fatal desync. Aborting playback. (Error in PlayWiimote: {0} != {1}, byte {2}.){3}", sizeInMovie, size, s_currentByte, - (s_controllers & 0xF) ? " Try re-creating the recording with all GameCube controllers " - "disabled (in Configure > GameCube > Device Settings)." : - ""); + (s_controllers == ControllerTypeArray{}) ? + " Try re-creating the recording with all GameCube controllers " + "disabled (in Configure > GameCube > Device Settings)." : + ""); EndPlayInput(!s_bReadOnly); return false; } @@ -1296,7 +1333,17 @@ void SaveRecording(const std::string& filename) strncpy(header.gameID.data(), SConfig::GetInstance().GetGameID().c_str(), 6); header.bWii = SConfig::GetInstance().bWii; header.bFollowBranch = SConfig::GetInstance().bJITFollowBranch; - header.controllers = s_controllers & (SConfig::GetInstance().bWii ? 0xFF : 0x0F); + header.controllers = 0; + header.GBAControllers = 0; + for (int i = 0; i < 4; ++i) + { + if (IsUsingGBA(i)) + header.GBAControllers |= 1 << i; + if (IsUsingPad(i)) + header.controllers |= 1 << i; + if (IsUsingWiimote(i) && SConfig::GetInstance().bWii) + header.controllers |= 1 << (i + 4); + } header.bFromSaveState = s_bRecordingFromSaveState; header.frameCount = s_totalFrames; diff --git a/Source/Core/Core/Movie.h b/Source/Core/Core/Movie.h index dcf70cef91..0a7857c0e3 100644 --- a/Source/Core/Core/Movie.h +++ b/Source/Core/Core/Movie.h @@ -39,6 +39,15 @@ enum PlayMode MODE_PLAYING }; +enum class ControllerType +{ + None = 0, + GC, + GBA, +}; +using ControllerTypeArray = std::array; +using WiimoteEnabledArray = std::array; + // GameCube Controller State #pragma pack(push, 1) struct ControllerState @@ -116,7 +125,8 @@ struct DTMHeader u8 reserved3; bool bFollowBranch; bool bUseFMA; - std::array reserved; // Padding for any new config options + u8 GBAControllers; // GBA Controllers plugged in (the bits are ports 1-4) + std::array reserved; // Padding for any new config options std::array discChange; // Name of iso file to switch to, for two disc games. std::array revision; // Git hash u32 DSPiromHash; @@ -163,12 +173,14 @@ bool IsNetPlayRecording(); bool IsUsingPad(int controller); bool IsUsingWiimote(int wiimote); bool IsUsingBongo(int controller); +bool IsUsingGBA(int controller); void ChangePads(); void ChangeWiiPads(bool instantly = false); void SetReadOnly(bool bEnabled); -bool BeginRecordingInput(int controllers); +bool BeginRecordingInput(const ControllerTypeArray& controllers, + const WiimoteEnabledArray& wiimotes); void RecordInput(const GCPadStatus* PadStatus, int controllerID); void RecordWiimote(int wiimote, const u8* data, u8 size); diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index 4212d3031e..e0e5a27518 100644 --- a/Source/Core/Core/NetPlayClient.cpp +++ b/Source/Core/Core/NetPlayClient.cpp @@ -1606,15 +1606,19 @@ bool NetPlayClient::StartGame(const std::string& path) if (Movie::IsReadOnly()) Movie::SetReadOnly(false); - u8 controllers_mask = 0; + Movie::ControllerTypeArray controllers{}; + Movie::WiimoteEnabledArray wiimotes{}; for (unsigned int i = 0; i < 4; ++i) { - if (m_pad_map[i] > 0) - controllers_mask |= (1 << i); - if (m_wiimote_map[i] > 0) - controllers_mask |= (1 << (i + 4)); + if (m_pad_map[i] > 0 && m_gba_config[i].enabled) + controllers[i] = Movie::ControllerType::GBA; + else if (m_pad_map[i] > 0) + controllers[i] = Movie::ControllerType::GC; + else + controllers[i] = Movie::ControllerType::None; + wiimotes[i] = m_wiimote_map[i] > 0; } - Movie::BeginRecordingInput(controllers_mask); + Movie::BeginRecordingInput(controllers, wiimotes); } for (unsigned int i = 0; i < 4; ++i) diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 317150812b..cd566b7624 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -1691,18 +1691,21 @@ void MainWindow::OnStartRecording() emit ReadOnlyModeChanged(true); } - int controllers = 0; + Movie::ControllerTypeArray controllers{}; + Movie::WiimoteEnabledArray wiimotes{}; for (int i = 0; i < 4; i++) { - if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i])) - controllers |= (1 << i); - - if (WiimoteCommon::GetSource(i) != WiimoteSource::None) - controllers |= (1 << (i + 4)); + if (SConfig::GetInstance().m_SIDevice[i] == SerialInterface::SIDEVICE_GC_GBA_EMULATED) + controllers[i] = Movie::ControllerType::GBA; + else if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i])) + controllers[i] = Movie::ControllerType::GC; + else + controllers[i] = Movie::ControllerType::None; + wiimotes[i] = WiimoteCommon::GetSource(i) != WiimoteSource::None; } - if (Movie::BeginRecordingInput(controllers)) + if (Movie::BeginRecordingInput(controllers, wiimotes)) { emit RecordingStatusChanged(true);