Movie: GBA Support

This commit is contained in:
Bonta
2021-07-04 13:38:30 +02:00
parent 45f2461a53
commit b8f0e97c02
5 changed files with 113 additions and 43 deletions

View File

@ -419,7 +419,11 @@ void Init()
{ {
s_desired_device_types[i] = SIDEVICE_NONE; 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]; SIDevices current = SConfig::GetInstance().m_SIDevice[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

View File

@ -82,7 +82,8 @@ static bool s_bReadOnly = true;
static u32 s_rerecords = 0; static u32 s_rerecords = 0;
static PlayMode s_playMode = MODE_NONE; static PlayMode s_playMode = MODE_NONE;
static u8 s_controllers = 0; static std::array<ControllerType, 4> s_controllers{};
static std::array<bool, 4> s_wiimotes{};
static ControllerState s_padState; static ControllerState s_padState;
static DTMHeader tmpHeader; static DTMHeader tmpHeader;
static std::vector<u8> s_temp_input; static std::vector<u8> s_temp_input;
@ -157,24 +158,33 @@ std::string GetInputDisplay()
{ {
if (!IsMovieActive()) if (!IsMovieActive())
{ {
s_controllers = 0; s_controllers = {};
s_wiimotes = {};
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
if (SerialInterface::GetDeviceType(i) != SerialInterface::SIDEVICE_NONE) if (SerialInterface::GetDeviceType(i) == SerialInterface::SIDEVICE_GC_GBA_EMULATED)
s_controllers |= (1 << i); s_controllers[i] = ControllerType::GBA;
if (WiimoteCommon::GetSource(i) != WiimoteSource::None) else if (SerialInterface::GetDeviceType(i) != SerialInterface::SIDEVICE_NONE)
s_controllers |= (1 << (i + 4)); s_controllers[i] = ControllerType::GC;
else
s_controllers[i] = ControllerType::None;
s_wiimotes[i] = WiimoteCommon::GetSource(i) != WiimoteSource::None;
} }
} }
std::string input_display; std::string input_display;
{ {
std::lock_guard guard(s_input_display_lock); 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'; 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; return input_display;
} }
@ -386,7 +396,7 @@ void SetReset(bool reset)
bool IsUsingPad(int controller) bool IsUsingPad(int controller)
{ {
return ((s_controllers & (1 << controller)) != 0); return s_controllers[controller] != ControllerType::None;
} }
bool IsUsingBongo(int controller) bool IsUsingBongo(int controller)
@ -394,9 +404,14 @@ bool IsUsingBongo(int controller)
return ((s_bongos & (1 << controller)) != 0); return ((s_bongos & (1 << controller)) != 0);
} }
bool IsUsingGBA(int controller)
{
return s_controllers[controller] == ControllerType::GBA;
}
bool IsUsingWiimote(int wiimote) bool IsUsingWiimote(int wiimote)
{ {
return ((s_controllers & (1 << (wiimote + 4))) != 0); return s_wiimotes[wiimote];
} }
bool IsConfigSaved() bool IsConfigSaved()
@ -425,21 +440,29 @@ void ChangePads()
if (!Core::IsRunning()) if (!Core::IsRunning())
return; return;
int controllers = 0; ControllerTypeArray controllers{};
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i) for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
{ {
if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i])) if (SConfig::GetInstance().m_SIDevice[i] == SerialInterface::SIDEVICE_GC_GBA_EMULATED)
controllers |= (1 << i); 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; return;
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i) for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
{ {
SerialInterface::SIDevices device = SerialInterface::SIDEVICE_NONE; 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])) if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i]))
{ {
@ -459,14 +482,15 @@ void ChangePads()
// NOTE: Host / Emu Threads // NOTE: Host / Emu Threads
void ChangeWiiPads(bool instantly) void ChangeWiiPads(bool instantly)
{ {
int controllers = 0; WiimoteEnabledArray wiimotes{};
for (int i = 0; i < MAX_WIIMOTES; ++i) 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 // 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; return;
const auto bt = WiiUtils::GetBluetoothEmuDevice(); const auto bt = WiiUtils::GetBluetoothEmuDevice();
@ -481,13 +505,16 @@ void ChangeWiiPads(bool instantly)
} }
// NOTE: Host Thread // 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; return false;
Core::RunAsCPUThread([controllers] { Core::RunAsCPUThread([controllers, wiimotes] {
s_controllers = controllers; s_controllers = controllers;
s_wiimotes = wiimotes;
s_currentFrame = s_totalFrames = 0; s_currentFrame = s_totalFrames = 0;
s_currentLagCount = s_totalLagCount = 0; s_currentLagCount = s_totalLagCount = 0;
s_currentInputCount = s_totalInputCount = 0; s_currentInputCount = s_totalInputCount = 0;
@ -842,7 +869,16 @@ void RecordWiimote(int wiimote, const u8* data, u8 size)
// NOTE: EmuThread / Host Thread // NOTE: EmuThread / Host Thread
void ReadHeader() 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; s_recordingStartTime = tmpHeader.recordingStartTime;
if (s_rerecords < tmpHeader.numRerecords) if (s_rerecords < tmpHeader.numRerecords)
s_rerecords = tmpHeader.numRerecords; s_rerecords = tmpHeader.numRerecords;
@ -1219,7 +1255,8 @@ bool PlayWiimote(int wiimote, WiimoteCommon::DataReportBuilder& rpt, int ext,
PanicAlertFmtT( PanicAlertFmtT(
"Fatal desync. Aborting playback. (Error in PlayWiimote: {0} != {1}, byte {2}.){3}", "Fatal desync. Aborting playback. (Error in PlayWiimote: {0} != {1}, byte {2}.){3}",
sizeInMovie, size, s_currentByte, sizeInMovie, size, s_currentByte,
(s_controllers & 0xF) ? " Try re-creating the recording with all GameCube controllers " (s_controllers == ControllerTypeArray{}) ?
" Try re-creating the recording with all GameCube controllers "
"disabled (in Configure > GameCube > Device Settings)." : "disabled (in Configure > GameCube > Device Settings)." :
""); "");
EndPlayInput(!s_bReadOnly); EndPlayInput(!s_bReadOnly);
@ -1296,7 +1333,17 @@ void SaveRecording(const std::string& filename)
strncpy(header.gameID.data(), SConfig::GetInstance().GetGameID().c_str(), 6); strncpy(header.gameID.data(), SConfig::GetInstance().GetGameID().c_str(), 6);
header.bWii = SConfig::GetInstance().bWii; header.bWii = SConfig::GetInstance().bWii;
header.bFollowBranch = SConfig::GetInstance().bJITFollowBranch; 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.bFromSaveState = s_bRecordingFromSaveState;
header.frameCount = s_totalFrames; header.frameCount = s_totalFrames;

View File

@ -39,6 +39,15 @@ enum PlayMode
MODE_PLAYING MODE_PLAYING
}; };
enum class ControllerType
{
None = 0,
GC,
GBA,
};
using ControllerTypeArray = std::array<ControllerType, 4>;
using WiimoteEnabledArray = std::array<bool, 4>;
// GameCube Controller State // GameCube Controller State
#pragma pack(push, 1) #pragma pack(push, 1)
struct ControllerState struct ControllerState
@ -116,7 +125,8 @@ struct DTMHeader
u8 reserved3; u8 reserved3;
bool bFollowBranch; bool bFollowBranch;
bool bUseFMA; bool bUseFMA;
std::array<u8, 8> reserved; // Padding for any new config options u8 GBAControllers; // GBA Controllers plugged in (the bits are ports 1-4)
std::array<u8, 7> reserved; // Padding for any new config options
std::array<char, 40> discChange; // Name of iso file to switch to, for two disc games. std::array<char, 40> discChange; // Name of iso file to switch to, for two disc games.
std::array<u8, 20> revision; // Git hash std::array<u8, 20> revision; // Git hash
u32 DSPiromHash; u32 DSPiromHash;
@ -163,12 +173,14 @@ bool IsNetPlayRecording();
bool IsUsingPad(int controller); bool IsUsingPad(int controller);
bool IsUsingWiimote(int wiimote); bool IsUsingWiimote(int wiimote);
bool IsUsingBongo(int controller); bool IsUsingBongo(int controller);
bool IsUsingGBA(int controller);
void ChangePads(); void ChangePads();
void ChangeWiiPads(bool instantly = false); void ChangeWiiPads(bool instantly = false);
void SetReadOnly(bool bEnabled); void SetReadOnly(bool bEnabled);
bool BeginRecordingInput(int controllers); bool BeginRecordingInput(const ControllerTypeArray& controllers,
const WiimoteEnabledArray& wiimotes);
void RecordInput(const GCPadStatus* PadStatus, int controllerID); void RecordInput(const GCPadStatus* PadStatus, int controllerID);
void RecordWiimote(int wiimote, const u8* data, u8 size); void RecordWiimote(int wiimote, const u8* data, u8 size);

View File

@ -1606,15 +1606,19 @@ bool NetPlayClient::StartGame(const std::string& path)
if (Movie::IsReadOnly()) if (Movie::IsReadOnly())
Movie::SetReadOnly(false); Movie::SetReadOnly(false);
u8 controllers_mask = 0; Movie::ControllerTypeArray controllers{};
Movie::WiimoteEnabledArray wiimotes{};
for (unsigned int i = 0; i < 4; ++i) for (unsigned int i = 0; i < 4; ++i)
{ {
if (m_pad_map[i] > 0) if (m_pad_map[i] > 0 && m_gba_config[i].enabled)
controllers_mask |= (1 << i); controllers[i] = Movie::ControllerType::GBA;
if (m_wiimote_map[i] > 0) else if (m_pad_map[i] > 0)
controllers_mask |= (1 << (i + 4)); 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) for (unsigned int i = 0; i < 4; ++i)

View File

@ -1691,18 +1691,21 @@ void MainWindow::OnStartRecording()
emit ReadOnlyModeChanged(true); emit ReadOnlyModeChanged(true);
} }
int controllers = 0; Movie::ControllerTypeArray controllers{};
Movie::WiimoteEnabledArray wiimotes{};
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i])) if (SConfig::GetInstance().m_SIDevice[i] == SerialInterface::SIDEVICE_GC_GBA_EMULATED)
controllers |= (1 << i); controllers[i] = Movie::ControllerType::GBA;
else if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i]))
if (WiimoteCommon::GetSource(i) != WiimoteSource::None) controllers[i] = Movie::ControllerType::GC;
controllers |= (1 << (i + 4)); 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); emit RecordingStatusChanged(true);