diff --git a/Data/Sys/GameSettings/SBEY.ini b/Data/Sys/GameSettings/SBEY.ini index 912626553a..2e79beb657 100644 --- a/Data/Sys/GameSettings/SBEY.ini +++ b/Data/Sys/GameSettings/SBEY.ini @@ -1,2 +1,4 @@ +# SBEY - Virtua Striker 2002 (Export, Japan, Type 3) + [Core] FPRF = True diff --git a/Data/Sys/GameSettings/SBGG.ini b/Data/Sys/GameSettings/SBGG.ini index 412b5048c7..6296633236 100644 --- a/Data/Sys/GameSettings/SBGG.ini +++ b/Data/Sys/GameSettings/SBGG.ini @@ -1,3 +1,5 @@ +# SBGG - F-ZERO AX + [Core] FPRF = True CPUThread = True diff --git a/Data/Sys/GameSettings/SBHA.ini b/Data/Sys/GameSettings/SBHA.ini index 412b5048c7..b62a599c92 100644 --- a/Data/Sys/GameSettings/SBHA.ini +++ b/Data/Sys/GameSettings/SBHA.ini @@ -1,3 +1,5 @@ +# SBHA - F-ZERO AX (Monster) + [Core] FPRF = True CPUThread = True diff --git a/Data/Sys/GameSettings/SBHN.ini b/Data/Sys/GameSettings/SBHN.ini index 912626553a..31be499dca 100644 --- a/Data/Sys/GameSettings/SBHN.ini +++ b/Data/Sys/GameSettings/SBHN.ini @@ -1,2 +1,4 @@ +# SBHN - VIRTUA STRIKER 4 VER.A + [Core] FPRF = True diff --git a/Data/Sys/GameSettings/SBHZ.ini b/Data/Sys/GameSettings/SBHZ.ini index 912626553a..a15b861658 100644 --- a/Data/Sys/GameSettings/SBHZ.ini +++ b/Data/Sys/GameSettings/SBHZ.ini @@ -1,2 +1,4 @@ +# SBHZ - VIRTUA STRIKER 4 (Asia) + [Core] FPRF = True diff --git a/Data/Sys/GameSettings/SBJA.ini b/Data/Sys/GameSettings/SBJA.ini index 912626553a..028fd4b6c0 100644 --- a/Data/Sys/GameSettings/SBJA.ini +++ b/Data/Sys/GameSettings/SBJA.ini @@ -1,2 +1,4 @@ +# SBJA - VIRTUA STRIKER 4 (Export) + [Core] FPRF = True diff --git a/Data/Sys/GameSettings/SBLK.ini b/Data/Sys/GameSettings/SBLK.ini index 912626553a..8931c60490 100644 --- a/Data/Sys/GameSettings/SBLK.ini +++ b/Data/Sys/GameSettings/SBLK.ini @@ -1,2 +1,4 @@ +# SBLK - VIRTUA STRIKER 4 Ver.2006 (Japan) + [Core] FPRF = True diff --git a/Data/Sys/GameSettings/SBLL.ini b/Data/Sys/GameSettings/SBLL.ini index 912626553a..deb8b08379 100644 --- a/Data/Sys/GameSettings/SBLL.ini +++ b/Data/Sys/GameSettings/SBLL.ini @@ -1,2 +1,4 @@ +# SBLL - VIRTUA STRIKER 4 Ver.2006 (Export) + [Core] FPRF = True diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index 57112245db..01a7a97caf 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -229,10 +229,7 @@ bool CBoot::RunApploader(Core::System& system, const Core::CPUThreadGuard& guard branch_watch.SetRecordingActive(guard, resume_branch_watch); - // Check for Triforce board being connected - const ExpansionInterface::EXIDeviceType Type = Config::Get(Config::MAIN_SERIAL_PORT_1); - bool enable_gcam = (Type == ExpansionInterface::EXIDeviceType::Baseboard) ? 1 : 0; - if (enable_gcam) + if (system.IsTriforce()) { auto& memory = system.GetMemory(); u32 dsize = volume.GetDataSize(); diff --git a/Source/Core/Core/HW/DVD/AMMediaboard.cpp b/Source/Core/Core/HW/DVD/AMMediaboard.cpp index 6aecfb6370..8af430f090 100644 --- a/Source/Core/Core/HW/DVD/AMMediaboard.cpp +++ b/Source/Core/Core/HW/DVD/AMMediaboard.cpp @@ -81,8 +81,7 @@ static int WSAGetLastError(void) namespace AMMediaboard { -static bool s_firmwaremap = false; -static bool s_segaboot = false; +static bool s_firmware_map = false; static bool s_test_menu = false; static SOCKET s_namco_cam = 0; static u32 s_timeouts[3] = {20000, 20000, 20000}; @@ -92,11 +91,11 @@ static u32 s_GCAM_key_a = 0; static u32 s_GCAM_key_b = 0; static u32 s_GCAM_key_c = 0; -static File::IOFile* s_netcfg = nullptr; -static File::IOFile* s_netctrl = nullptr; -static File::IOFile* s_extra = nullptr; -static File::IOFile* s_backup = nullptr; -static File::IOFile* s_dimm = nullptr; +static File::IOFile s_netcfg = nullptr; +static File::IOFile s_netctrl = nullptr; +static File::IOFile s_extra = nullptr; +static File::IOFile s_backup = nullptr; +static File::IOFile s_dimm = nullptr; static u8* s_dimm_disc = nullptr; @@ -157,7 +156,7 @@ static inline void PrintMBBuffer(u32 address, u32 length) void FirmwareMap(bool on) { - s_firmwaremap = on; + s_firmware_map = on; } void InitKeys(u32 key_a, u32 key_b, u32 key_c) @@ -167,14 +166,14 @@ void InitKeys(u32 key_a, u32 key_b, u32 key_c) s_GCAM_key_c = key_c; } -static File::IOFile* OpenOrCreateFile(const std::string& filename) +static File::IOFile OpenOrCreateFile(const std::string& filename) { // Try opening for read/write first if (File::Exists(filename)) - return new File::IOFile(filename, "rb+"); + return File::IOFile(filename, "rb+"); // Create new file - return new File::IOFile(filename, "wb+"); + return File::IOFile(filename, "wb+"); } void Init(void) @@ -185,8 +184,7 @@ void Init(void) memset(s_firmware, -1, sizeof(s_firmware)); memset(s_sockets, SOCKET_ERROR, sizeof(s_sockets)); - s_segaboot = false; - s_firmwaremap = false; + s_firmware_map = false; s_test_menu = false; s_last_error = SSC_SUCCESS; @@ -203,15 +201,15 @@ void Init(void) s_dimm = OpenOrCreateFile(base_path + "tridimm_" + SConfig::GetInstance().GetGameID() + ".bin"); s_backup = OpenOrCreateFile(base_path + "backup_" + SConfig::GetInstance().GetGameID() + ".bin"); - if (!s_netcfg) + if (!s_netcfg.IsOpen()) PanicAlertFmt("Failed to open/create: {}", base_path + "s_netcfg.bin"); - if (!s_netctrl) + if (!s_netctrl.IsOpen()) PanicAlertFmt("Failed to open/create: {}", base_path + "s_netctrl.bin"); - if (!s_extra) + if (!s_extra.IsOpen()) PanicAlertFmt("Failed to open/create: {}", base_path + "s_extra.bin"); - if (!s_dimm) + if (!s_dimm.IsOpen()) PanicAlertFmt("Failed to open/create: {}", base_path + "s_dimm.bin"); - if (!s_backup) + if (!s_backup.IsOpen()) PanicAlertFmt("Failed to open/create: {}", base_path + "s_backup.bin"); // This is the firmware for the Triforce @@ -252,7 +250,7 @@ u8* InitDIMM(u32 size) } } - s_firmwaremap = 0; + s_firmware_map = 0; return s_dimm_disc; } @@ -396,7 +394,7 @@ static void FileWriteData(File::IOFile* file, u32 seek_pos, const u8* data, size file->WriteBytes(data, length); file->Flush(); } -u32 ExecuteCommand(std::array& DICMDBUF, u32 address, u32 length) +u32 ExecuteCommand(std::array& DICMDBUF, u32* DIIMMBUF, u32 address, u32 length) { auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); @@ -413,8 +411,8 @@ u32 ExecuteCommand(std::array& DICMDBUF, u32 address, u32 length) /* Key setup for Triforce IPL: - These RAM offset always hold the keys for the next command and since it sends two dummy - commands before a real read we can just use the key from RAM without missing any real commands. +These RAM offsets always hold the key for the next command. Since two dummy commands are sent before +any real ones, you can just use the key from RAM without missing a real command. */ if (s_GCAM_key_a == 0) { @@ -430,13 +428,6 @@ u32 ExecuteCommand(std::array& DICMDBUF, u32 address, u32 length) u32 command = DICMDBUF[0] << 24; u32 offset = DICMDBUF[1] << 2; - // SegaBoot adds bits for some reason to offset/length - // also adds 0x20 to offset - if (offset == 0x00100440) - { - s_segaboot = true; - } - INFO_LOG_FMT(DVDINTERFACE_AMMB, "GC-AM: {:08x} {:08x} DMA=addr:{:08x},len:{:08x} Keys: {:08x} {:08x} {:08x}", command, offset, address, length, s_GCAM_key_a, s_GCAM_key_b, s_GCAM_key_c); @@ -450,33 +441,34 @@ u32 ExecuteCommand(std::array& DICMDBUF, u32 address, u32 length) // Don't map firmware while in SegaBoot if (memory.Read_U32(0x8006BF70) != 0x0A536567) { - s_firmwaremap = 1; + s_firmware_map = 1; } } } - switch (AMMBCommand(command >> 24)) + switch (AMMBDICommand(command >> 24)) { - case AMMBCommand::Inquiry: - if (s_firmwaremap) + case AMMBDICommand::Inquiry: + if (s_firmware_map) { - s_firmwaremap = false; - s_segaboot = false; + s_firmware_map = false; } // Returned value is used to set the protocol version. switch (GetGameType()) { default: - return Version1; + *DIIMMBUF = Version1; + return 0; case KeyOfAvalon: case MarioKartGP: case MarioKartGP2: case FirmwareUpdate: - return Version2; + *DIIMMBUF = Version2; + return 0; } break; - case AMMBCommand::Read: + case AMMBDICommand::Read: if ((offset & 0x8FFF0000) == 0x80000000) { switch (offset) @@ -523,16 +515,16 @@ u32 ExecuteCommand(std::array& DICMDBUF, u32 address, u32 length) // Network configuration if (offset == 0x00000000 && length == 0x80) { - s_netcfg->Seek(0, File::SeekOrigin::Begin); - s_netcfg->ReadBytes(memory.GetSpanForAddress(address).data(), length); + s_netcfg.Seek(0, File::SeekOrigin::Begin); + s_netcfg.ReadBytes(memory.GetSpanForAddress(address).data(), length); return 0; } // media crc check on/off if (offset == DIMMExtraSettings && length == 0x20) { - s_extra->Seek(0, File::SeekOrigin::Begin); - s_extra->ReadBytes(memory.GetSpanForAddress(address).data(), length); + s_extra.Seek(0, File::SeekOrigin::Begin); + s_extra.ReadBytes(memory.GetSpanForAddress(address).data(), length); return 0; } @@ -540,8 +532,8 @@ u32 ExecuteCommand(std::array& DICMDBUF, u32 address, u32 length) if (offset >= DIMMMemory && offset <= 0x1F800000) { u32 dimmoffset = offset - DIMMMemory; - s_dimm->Seek(dimmoffset, File::SeekOrigin::Begin); - s_dimm->ReadBytes(memory.GetSpanForAddress(address).data(), length); + s_dimm.Seek(dimmoffset, File::SeekOrigin::Begin); + s_dimm.ReadBytes(memory.GetSpanForAddress(address).data(), length); return 0; } @@ -1044,15 +1036,15 @@ u32 ExecuteCommand(std::array& DICMDBUF, u32 address, u32 length) if (offset >= DIMMMemory2 && offset <= 0xFF800000) { u32 dimmoffset = offset - DIMMMemory2; - s_dimm->Seek(dimmoffset, File::SeekOrigin::Begin); - s_dimm->ReadBytes(memory.GetSpanForAddress(address).data(), length); + s_dimm.Seek(dimmoffset, File::SeekOrigin::Begin); + s_dimm.ReadBytes(memory.GetSpanForAddress(address).data(), length); return 0; } if (offset == NetworkControl && length == 0x20) { - s_netctrl->Seek(0, File::SeekOrigin::Begin); - s_netctrl->ReadBytes(memory.GetSpanForAddress(address).data(), length); + s_netctrl.Seek(0, File::SeekOrigin::Begin); + s_netctrl.ReadBytes(memory.GetSpanForAddress(address).data(), length); return 0; } @@ -1063,13 +1055,8 @@ u32 ExecuteCommand(std::array& DICMDBUF, u32 address, u32 length) return 0; } - if (s_firmwaremap) + if (s_firmware_map) { - if (s_segaboot) - { - DICMDBUF[1] &= ~0x00100000; - DICMDBUF[1] -= 0x20; - } memcpy(memory.GetSpanForAddress(address).data(), s_firmware + offset, length); return 0; } @@ -1082,23 +1069,23 @@ u32 ExecuteCommand(std::array& DICMDBUF, u32 address, u32 length) return 1; break; - case AMMBCommand::Write: + case AMMBDICommand::Write: /* These two magic writes allow a new firmware to be programmed */ if ((offset == FirmwareMagicWrite1) && (length == 0x20)) { - s_firmwaremap = true; + s_firmware_map = true; return 0; } if ((offset == FirmwareMagicWrite2) && (length == 0x20)) { - s_firmwaremap = true; + s_firmware_map = true; return 0; } - if (s_firmwaremap) + if (s_firmware_map) { // Firmware memory (2MB) if ((offset >= 0x00400000) && (offset <= 0x600000)) @@ -1112,21 +1099,21 @@ u32 ExecuteCommand(std::array& DICMDBUF, u32 address, u32 length) // Network configuration if ((offset == 0x00000000) && (length == 0x80)) { - FileWriteData(s_netcfg, 0, memory.GetSpanForAddress(address).data(), length); + FileWriteData(&s_netcfg, 0, memory.GetSpanForAddress(address).data(), length); return 0; } // media crc check on/off if ((offset == DIMMExtraSettings) && (length == 0x20)) { - FileWriteData(s_extra, 0, memory.GetSpanForAddress(address).data(), length); + FileWriteData(&s_extra, 0, memory.GetSpanForAddress(address).data(), length); return 0; } // Backup memory (8MB) if ((offset >= BackupMemory) && (offset <= 0x00800000)) { - FileWriteData(s_backup, 0, memory.GetSpanForAddress(address).data(), length); + FileWriteData(&s_backup, 0, memory.GetSpanForAddress(address).data(), length); return 0; } @@ -1134,7 +1121,7 @@ u32 ExecuteCommand(std::array& DICMDBUF, u32 address, u32 length) if ((offset >= DIMMMemory) && (offset <= 0x1F800000)) { u32 dimmoffset = offset - DIMMMemory; - FileWriteData(s_dimm, dimmoffset, memory.GetSpanForAddress(address).data(), length); + FileWriteData(&s_dimm, dimmoffset, memory.GetSpanForAddress(address).data(), length); return 0; } @@ -1320,13 +1307,13 @@ u32 ExecuteCommand(std::array& DICMDBUF, u32 address, u32 length) if ((offset >= DIMMMemory2) && (offset <= 0xFF800000)) { u32 dimmoffset = offset - 0xFF000000; - FileWriteData(s_dimm, dimmoffset, memory.GetSpanForAddress(address).data(), length); + FileWriteData(&s_dimm, dimmoffset, memory.GetSpanForAddress(address).data(), length); return 0; } if ((offset == NetworkControl) && (length == 0x20)) { - FileWriteData(s_netctrl, 0, memory.GetSpanForAddress(address).data(), length); + FileWriteData(&s_netctrl, 0, memory.GetSpanForAddress(address).data(), length); return 0; } @@ -1337,7 +1324,7 @@ u32 ExecuteCommand(std::array& DICMDBUF, u32 address, u32 length) PanicAlertFmtT("Unhandled Media Board Write:{0:08x}", offset); } break; - case AMMBCommand::Execute: + case AMMBDICommand::Execute: if ((offset == 0) && (length == 0)) { // Recast for easier access @@ -1818,20 +1805,11 @@ bool GetTestMenu(void) } void Shutdown(void) { - if (s_netcfg) - s_netcfg->Close(); - - if (s_netctrl) - s_netctrl->Close(); - - if (s_extra) - s_extra->Close(); - - if (s_backup) - s_backup->Close(); - - if (s_dimm) - s_dimm->Close(); + s_netcfg.Close(); + s_netctrl.Close(); + s_extra.Close(); + s_backup.Close(); + s_dimm.Close(); if (s_dimm_disc) { diff --git a/Source/Core/Core/HW/DVD/AMMediaboard.h b/Source/Core/Core/HW/DVD/AMMediaboard.h index 192a551331..d41894f23a 100644 --- a/Source/Core/Core/HW/DVD/AMMediaboard.h +++ b/Source/Core/Core/HW/DVD/AMMediaboard.h @@ -32,7 +32,7 @@ enum GameType VirtuaStriker4, GekitouProYakyuu, KeyOfAvalon, - FirmwareUpdate + FirmwareUpdate, }; enum MediaType { @@ -54,28 +54,32 @@ enum MediaBoardStatus TestingGameProgram = 3, LoadingGameProgram = 4, LoadedGameProgram = 5, - Error = 6 + Error = 6, }; enum InquiryType { Version1 = 0x21484100, - Version2 = 0x29484100 + Version2 = 0x29484100, }; #define SocketCheck(x) (x <= 0x3F ? x : 0) namespace AMMediaboard { + +enum class AMMBDICommand : u16 +{ + Inquiry = 0x12, + Read = 0xA8, + Write = 0xAA, + Execute = 0xAB, +}; + enum class AMMBCommand : u16 { Unknown_000 = 0x000, GetDIMMSize = 0x001, - Inquiry = 0x12, - Read = 0xa8, - Write = 0xaa, - Execute = 0xab, - GetMediaBoardStatus = 0x100, GetSegaBootVersion = 0x101, GetSystemFlags = 0x102, @@ -209,7 +213,7 @@ void Init(void); void FirmwareMap(bool on); u8* InitDIMM(u32 size); void InitKeys(u32 KeyA, u32 KeyB, u32 KeyC); -u32 ExecuteCommand(std::array& DICMDBUF, u32 Address, u32 Length); +u32 ExecuteCommand(std::array& DICMDBUF, u32* DIIMMBUF, u32 Address, u32 Length); u32 GetGameType(void); u32 GetMediaType(void); bool GetTestMenu(void); diff --git a/Source/Core/Core/HW/DVD/DVDInterface.cpp b/Source/Core/Core/HW/DVD/DVDInterface.cpp index 6b81eafa08..5ed8e03524 100644 --- a/Source/Core/Core/HW/DVD/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVD/DVDInterface.cpp @@ -766,12 +766,8 @@ void DVDInterface::ExecuteCommand(ReplyType reply_type) if (m_system.IsTriforce()) { - u32 ret = AMMediaboard::ExecuteCommand(m_DICMDBUF, m_DIMAR, m_DILENGTH); - if (ret != 1) + if (!AMMediaboard::ExecuteCommand(m_DICMDBUF, &m_DIIMMBUF, m_DIMAR, m_DILENGTH)) { - if (m_DICMDBUF[0] == 0x12000000) - m_DIIMMBUF = ret; - // Transfer is done m_DICR.TSTART = 0; m_DIMAR += m_DILENGTH; @@ -784,15 +780,6 @@ void DVDInterface::ExecuteCommand(ReplyType reply_type) // Normal read command pass on to normal handling } - // Swaps endian of Triforce DI commands, and zeroes out random bytes to prevent unknown read - // subcommand errors - auto& dvd_thread = m_system.GetDVDThread(); - if (dvd_thread.HasDisc() && dvd_thread.GetDiscType() == DiscIO::Platform::Triforce) - { - // TODO(C++23): Use std::byteswap and a bitwise AND for increased clarity - m_DICMDBUF[0] <<= 24; - } - // DVDLowRequestError needs access to the error code set by the previous command if (static_cast(m_DICMDBUF[0] >> 24) != DICommand::RequestError) SetDriveError(DriveError::None); diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceBaseboard.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceBaseboard.cpp index e728aaf250..46aff6f009 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceBaseboard.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceBaseboard.cpp @@ -16,6 +16,7 @@ #include "Common/IOFile.h" #include "Common/IniFile.h" #include "Common/Logging/Log.h" +#include "Common/Buffer.h" #include "Core/Boot/Boot.h" #include "Core/BootManager.h" #include "Core/Config/MainSettings.h" @@ -76,17 +77,14 @@ CEXIBaseboard::CEXIBaseboard(Core::System& system) : IEXIDevice(system), m_posit std::string backup_Filename(File::GetUserPath(D_TRIUSER_IDX) + "tribackup_" + SConfig::GetInstance().GetGameID().c_str() + ".bin"); - if (File::Exists(backup_Filename)) + m_backup = File::IOFile(backup_Filename, "rb+"); + if (!m_backup.IsOpen()) { - m_backup = new File::IOFile(backup_Filename, "rb+"); - } - else - { - m_backup = new File::IOFile(backup_Filename, "wb+"); + m_backup = File::IOFile(backup_Filename, "wb+"); } // Some games share the same ID Client/Server - if (!m_backup->IsGood()) + if (!m_backup.IsGood()) { PanicAlertFmt("Failed to open {}\nFile might be in use.", backup_Filename.c_str()); @@ -95,7 +93,7 @@ CEXIBaseboard::CEXIBaseboard(Core::System& system) : IEXIDevice(system), m_posit backup_Filename = File::GetUserPath(D_TRIUSER_IDX) + "tribackup_tmp_" + std::to_string(rand()) + SConfig::GetInstance().GetGameID().c_str() + ".bin"; - m_backup = new File::IOFile(backup_Filename, "wb+"); + m_backup = File::IOFile(backup_Filename, "wb+"); } // Virtua Striker 4 and Gekitou Pro Yakyuu need a higher FIRM version @@ -103,32 +101,28 @@ CEXIBaseboard::CEXIBaseboard(Core::System& system) : IEXIDevice(system), m_posit if (AMMediaboard::GetGameType() == VirtuaStriker4 || AMMediaboard::GetGameType() == GekitouProYakyuu) { - if (m_backup->GetSize() != 0) + if (m_backup.GetSize() != 0) { - u8* data = new u8[m_backup->GetSize()]; - - m_backup->ReadBytes(data, m_backup->GetSize()); + Common::UniqueBuffer data(m_backup.GetSize()); + m_backup.ReadBytes(data.data(), data.size()); // Set FIRM version - *(u16*)(data + 0x12) = 0x1703; - *(u16*)(data + 0x212) = 0x1703; + reinterpret_cast(data[0x12]) = 0x1703; + reinterpret_cast(data[0x212]) = 0x1703; // Update checksum - *(u16*)(data + 0x0A) = Common::swap16(CheckSum(data + 0xC, 0x1F4)); - *(u16*)(data + 0x20A) = Common::swap16(CheckSum(data + 0x20C, 0x1F4)); + reinterpret_cast(data[0x0A]) = Common::swap16(CheckSum(&data[0xC], 0x1F4)); + reinterpret_cast(data[0x20A]) = Common::swap16(CheckSum(&data[0x20C], 0x1F4)); - m_backup->Seek(0, File::SeekOrigin::Begin); - m_backup->WriteBytes(data, m_backup->GetSize()); - m_backup->Flush(); - - delete[] data; + m_backup.Seek(0, File::SeekOrigin::Begin); + m_backup.WriteBytes(data.data(), data.size()); + m_backup.Flush(); } } } CEXIBaseboard::~CEXIBaseboard() { - m_backup->Close(); - delete m_backup; + m_backup.Close(); } void CEXIBaseboard::SetCS(int cs) @@ -165,11 +159,11 @@ void CEXIBaseboard::DMAWrite(u32 addr, u32 size) NOTICE_LOG_FMT(SP1, "AM-BB: COMMAND: Backup DMA Write: {:08x} {:x}", addr, size); - m_backup->Seek(m_backoffset, File::SeekOrigin::Begin); + m_backup.Seek(m_backoffset, File::SeekOrigin::Begin); - m_backup->WriteBytes(memory.GetSpanForAddress(addr).data(), size); + m_backup.WriteBytes(memory.GetSpanForAddress(addr).data(), size); - m_backup->Flush(); + m_backup.Flush(); } void CEXIBaseboard::DMARead(u32 addr, u32 size) @@ -179,11 +173,11 @@ void CEXIBaseboard::DMARead(u32 addr, u32 size) NOTICE_LOG_FMT(SP1, "AM-BB: COMMAND: Backup DMA Read: {:08x} {:x}", addr, size); - m_backup->Seek(m_backoffset, File::SeekOrigin::Begin); + m_backup.Seek(m_backoffset, File::SeekOrigin::Begin); - m_backup->Flush(); + m_backup.Flush(); - m_backup->ReadBytes(memory.GetSpanForAddress(addr).data(), size); + m_backup.ReadBytes(memory.GetSpanForAddress(addr).data(), size); } void CEXIBaseboard::TransferByte(u8& _byte) @@ -225,13 +219,13 @@ void CEXIBaseboard::TransferByte(u8& _byte) case BackupOffsetSet: m_backoffset = (m_command[1] << 8) | m_command[2]; DEBUG_LOG_FMT(SP1, "AM-BB: COMMAND: BackupOffsetSet:{:04x}", m_backoffset); - m_backup->Seek(m_backoffset, File::SeekOrigin::Begin); + m_backup.Seek(m_backoffset, File::SeekOrigin::Begin); _byte = 0x01; break; case BackupWrite: DEBUG_LOG_FMT(SP1, "AM-BB: COMMAND: BackupWrite:{:04x}-{:02x}", m_backoffset, m_command[1]); - m_backup->WriteBytes(&m_command[1], 1); - m_backup->Flush(); + m_backup.WriteBytes(&m_command[1], 1); + m_backup.Flush(); _byte = 0x01; break; case BackupRead: @@ -292,8 +286,8 @@ void CEXIBaseboard::TransferByte(u8& _byte) { // 1 byte out case BackupRead: - m_backup->Flush(); - m_backup->ReadBytes(&_byte, 1); + m_backup.Flush(); + m_backup.ReadBytes(&_byte, 1); break; case DMAOffsetLengthSet: _byte = 0x01; diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceBaseboard.h b/Source/Core/Core/HW/EXI/EXI_DeviceBaseboard.h index 8fdc7d8ffd..ccc8b45a8f 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceBaseboard.h +++ b/Source/Core/Core/HW/EXI/EXI_DeviceBaseboard.h @@ -59,7 +59,7 @@ private: u32 m_backup_dma_length; u8 m_command[4]; u16 m_backoffset; - File::IOFile* m_backup; + File::IOFile m_backup; protected: void TransferByte(u8& _uByte) override; diff --git a/Source/Core/Core/HW/GCPadEmu.h b/Source/Core/Core/HW/GCPadEmu.h index 1918b34659..6e244d139f 100644 --- a/Source/Core/Core/HW/GCPadEmu.h +++ b/Source/Core/Core/HW/GCPadEmu.h @@ -30,7 +30,7 @@ enum class PadGroup Rumble, Mic, Options, - Triforce + Triforce, }; class GCPad : public ControllerEmu::EmulatedController diff --git a/Source/Core/Core/HW/SI/SI_Device.cpp b/Source/Core/Core/HW/SI/SI_Device.cpp index 2bfd150bea..c826cf345b 100644 --- a/Source/Core/Core/HW/SI/SI_Device.cpp +++ b/Source/Core/Core/HW/SI/SI_Device.cpp @@ -140,6 +140,7 @@ bool SIDevice_IsGCController(SIDevices type) case SIDEVICE_GC_TARUKONGA: case SIDEVICE_DANCEMAT: case SIDEVICE_GC_STEERING: + case SIDEVICE_AM_BASEBOARD: return true; default: return false; diff --git a/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.cpp b/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.cpp index cf8f833a48..9675d2d50e 100644 --- a/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.cpp +++ b/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.cpp @@ -13,6 +13,8 @@ #include +#include "Common/Buffer.h" +#include "Common/ChunkFile.h" #include "Common/CommonTypes.h" #include "Common/Config/Config.h" #include "Common/FileUtil.h" @@ -20,6 +22,8 @@ #include "Common/IOFile.h" #include "Common/IniFile.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" +#include "Common/Swap.h" #include "Core/Boot/Boot.h" #include "Core/BootManager.h" #include "Core/Config/MainSettings.h" @@ -28,15 +32,19 @@ #include "Core/ConfigLoaders/NetPlayConfigLoader.h" #include "Core/ConfigManager.h" #include "Core/Core.h" +#include "Core/CoreTiming.h" #include "Core/HW/DVD/AMMediaboard.h" #include "Core/HW/DVD/DVDInterface.h" #include "Core/HW/EXI/EXI.h" +#include "Core/HW/GCPad.h" #include "Core/HW/MMIO.h" #include "Core/HW/Memmap.h" +#include "Core/HW/ProcessorInterface.h" #include "Core/HW/SI/SI.h" #include "Core/HW/SI/SI_Device.h" #include "Core/HW/SI/SI_DeviceGCController.h" #include "Core/HW/Sram.h" +#include "Core/HW/SystemTimers.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" #include "Core/Movie.h" #include "Core/NetPlayProto.h" @@ -44,6 +52,7 @@ #include "Core/System.h" #include "Core/WiiRoot.h" #include "DiscIO/Enums.h" +#include "InputCommon/GCPadStatus.h" namespace SerialInterface { @@ -1997,7 +2006,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length) break; } - u8* buf = new u8[bytes]; + Common::UniqueBuffer buf(bytes); for (u32 i = 0; i < bytes; ++i) { @@ -2008,32 +2017,12 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length) SERIALINTERFACE_JVSIO, "JVS-IO: Command 0x32, GPO: {:02x} {:02x} {} {:02x}{:02x}{:02x} ({:02x})", delay, m_rx_reply, bytes, buf[0], buf[1], buf[2], - Common::swap16(*(u16*)(buf + 1)) >> 2); + Common::swap16(*reinterpret_cast(&buf[1])) >> 2); - // TODO: figure this out - - u8 trepl[] = { - 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, - 0xD0, 0xE0, 0xF0, 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, - 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, - 0x72, 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2, 0x04, 0x14, 0x24, 0x34, - 0x44, 0x54, 0x64, 0x74, 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4, 0x05, - 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, - 0xE5, 0xF5, 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, 0x86, 0x96, 0xA6, - 0xB6, 0xC6, 0xD6, 0xE6, 0xF6, 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, - 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8, 0x09, 0x19, 0x29, 0x39, 0x49, - 0x59, 0x69, 0x79, 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9, 0x0A, 0x1A, - 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A, 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, - 0xFA, 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, 0x8C, 0x9C, 0xAC, 0xBC, - 0xCC, 0xDC, 0xEC, 0xFC, 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D, 0x8D, - 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD, 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, - 0x6E, 0x7E, 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE}; - - static u32 off = 0; - if (off > sizeof(trepl)) - off = 0; - - switch (Common::swap16(*(u16*)(buf + 1)) >> 2) + /* + Handling of the motion seat used in F-Zero AXs DX version + */ + switch (Common::swap16(*reinterpret_cast(&buf[1])) >> 2) { case 0x70: delay++; @@ -2050,13 +2039,6 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length) case 0x60: break; } - ////if( buf[1] == 1 && buf[2] == 0x80 ) - ////{ - //// INFO_LOG_FMT(DVDINTERFACE, "GCAM: PC:{:08x}", PC); - //// PowerPC::breakpoints.Add( PC+8, false ); - ////} - - delete[] buf; } break; } @@ -2080,7 +2062,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length) else { message.addData(StatusOkay); - ERROR_LOG_FMT(SERIALINTERFACE_JVSIO, "JVS-IO:Unknown:{:02x}", cmd_); + ERROR_LOG_FMT(SERIALINTERFACE_JVSIO, "JVS-IO: Unknown:{:02x}", cmd_); } break; } @@ -2170,19 +2152,210 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length) return buffer_position; } -// Unused -DataResponse CSIDevice_AMBaseboard::GetData(u32& _Hi, u32& _Low) +u32 CSIDevice_AMBaseboard::MapPadStatus(const GCPadStatus& pad_status) { - _Low = 0; - _Hi = 0x00800000; + // Thankfully changing mode does not change the high bits ;) + u32 hi = 0; + hi = pad_status.stickY; + hi |= pad_status.stickX << 8; + hi |= (pad_status.button | PAD_USE_ORIGIN) << 16; + return hi; +} + +CSIDevice_AMBaseboard::EButtonCombo +CSIDevice_AMBaseboard::HandleButtonCombos(const GCPadStatus& pad_status) +{ + // Keep track of the special button combos (embedded in controller hardware... :( ) + EButtonCombo temp_combo; + if ((pad_status.button & 0xff00) == (PAD_BUTTON_Y | PAD_BUTTON_X | PAD_BUTTON_START)) + temp_combo = COMBO_ORIGIN; + else if ((pad_status.button & 0xff00) == (PAD_BUTTON_B | PAD_BUTTON_X | PAD_BUTTON_START)) + temp_combo = COMBO_RESET; + else + temp_combo = COMBO_NONE; + + if (temp_combo != m_last_button_combo) + { + m_last_button_combo = temp_combo; + if (m_last_button_combo != COMBO_NONE) + m_timer_button_combo_start = m_system.GetCoreTiming().GetTicks(); + } + + if (m_last_button_combo != COMBO_NONE) + { + const u64 current_time = m_system.GetCoreTiming().GetTicks(); + const u32 ticks_per_second = m_system.GetSystemTimers().GetTicksPerSecond(); + if (u32(current_time - m_timer_button_combo_start) > ticks_per_second * 3) + { + if (m_last_button_combo == COMBO_RESET) + { + INFO_LOG_FMT(SERIALINTERFACE, "PAD - COMBO_RESET"); + m_system.GetProcessorInterface().ResetButton_Tap(); + } + else if (m_last_button_combo == COMBO_ORIGIN) + { + INFO_LOG_FMT(SERIALINTERFACE, "PAD - COMBO_ORIGIN"); + SetOrigin(pad_status); + } + + m_last_button_combo = COMBO_NONE; + return temp_combo; + } + } + + return COMBO_NONE; +} + +// GetData + +// Return true on new data (max 7 Bytes and 6 bits ;) +// [00?SYXBA] [1LRZUDRL] [x] [y] [cx] [cy] [l] [r] +// |\_ ERR_LATCH (error latched - check SISR) +// |_ ERR_STATUS (error on last GetData or SendCmd?) +DataResponse CSIDevice_AMBaseboard::GetData(u32& hi, u32& low) +{ + GCPadStatus pad_status = GetPadStatus(); + + if (!pad_status.isConnected) + return DataResponse::ErrorNoResponse; + + if (HandleButtonCombos(pad_status) == COMBO_ORIGIN) + pad_status.button |= PAD_GET_ORIGIN; + + hi = MapPadStatus(pad_status); + + // Low bits are packed differently per mode + if (m_mode == 0 || m_mode == 5 || m_mode == 6 || m_mode == 7) + { + low = (pad_status.analogB >> 4); // Top 4 bits + low |= ((pad_status.analogA >> 4) << 4); // Top 4 bits + low |= ((pad_status.triggerRight >> 4) << 8); // Top 4 bits + low |= ((pad_status.triggerLeft >> 4) << 12); // Top 4 bits + low |= ((pad_status.substickY) << 16); // All 8 bits + low |= ((pad_status.substickX) << 24); // All 8 bits + } + else if (m_mode == 1) + { + low = (pad_status.analogB >> 4); // Top 4 bits + low |= ((pad_status.analogA >> 4) << 4); // Top 4 bits + low |= (pad_status.triggerRight << 8); // All 8 bits + low |= (pad_status.triggerLeft << 16); // All 8 bits + low |= ((pad_status.substickY >> 4) << 24); // Top 4 bits + low |= ((pad_status.substickX >> 4) << 28); // Top 4 bits + } + else if (m_mode == 2) + { + low = pad_status.analogB; // All 8 bits + low |= pad_status.analogA << 8; // All 8 bits + low |= ((pad_status.triggerRight >> 4) << 16); // Top 4 bits + low |= ((pad_status.triggerLeft >> 4) << 20); // Top 4 bits + low |= ((pad_status.substickY >> 4) << 24); // Top 4 bits + low |= ((pad_status.substickX >> 4) << 28); // Top 4 bits + } + else if (m_mode == 3) + { + // Analog A/B are always 0 + low = pad_status.triggerRight; // All 8 bits + low |= (pad_status.triggerLeft << 8); // All 8 bits + low |= (pad_status.substickY << 16); // All 8 bits + low |= (pad_status.substickX << 24); // All 8 bits + } + else if (m_mode == 4) + { + low = pad_status.analogB; // All 8 bits + low |= pad_status.analogA << 8; // All 8 bits + // triggerLeft/Right are always 0 + low |= pad_status.substickY << 16; // All 8 bits + low |= pad_status.substickX << 24; // All 8 bits + } return DataResponse::Success; } -void CSIDevice_AMBaseboard::SendCommand(u32 _Cmd, u8 _Poll) +void CSIDevice_AMBaseboard::SendCommand(u32 command, u8 poll) { - ERROR_LOG_FMT(SERIALINTERFACE, "Unknown direct command (0x{})", _Cmd); - PanicAlertFmt("SI: (GCAM) Unknown direct command"); + UCommand controller_command(command); + + if (static_cast(controller_command.command) == EDirectCommands::CMD_WRITE) + { + const u32 type = controller_command.parameter1; // 0 = stop, 1 = rumble, 2 = stop hard + + // get the correct pad number that should rumble locally when using netplay + const int pad_num = NetPlay_InGamePadToLocalPad(m_device_number); + + if (pad_num < 4) + { + const SIDevices device = m_system.GetSerialInterface().GetDeviceType(pad_num); + if (type == 1) + CSIDevice_GCController::Rumble(pad_num, 1.0, device); + else + CSIDevice_GCController::Rumble(pad_num, 0.0, device); + } + + if (poll == 0) + { + m_mode = controller_command.parameter2; + INFO_LOG_FMT(SERIALINTERFACE, "PAD {} set to mode {}", m_device_number, m_mode); + } + } + else if (controller_command.command != 0x00) + { + // Costis sent 0x00 in some demos :) + ERROR_LOG_FMT(SERIALINTERFACE, "Unknown direct command ({:#x})", command); + PanicAlertFmt("SI: Unknown direct command"); + } +} + +void CSIDevice_AMBaseboard::SetOrigin(const GCPadStatus& pad_status) +{ + m_origin.origin_stick_x = pad_status.stickX; + m_origin.origin_stick_y = pad_status.stickY; + m_origin.substick_x = pad_status.substickX; + m_origin.substick_y = pad_status.substickY; + m_origin.trigger_left = pad_status.triggerLeft; + m_origin.trigger_right = pad_status.triggerRight; +} + +void CSIDevice_AMBaseboard::HandleMoviePadStatus(Movie::MovieManager& movie, int device_number, + GCPadStatus* pad_status) +{ + movie.SetPolledDevice(); + if (NetPlay_GetInput(device_number, pad_status)) + { + } + else if (movie.IsPlayingInput()) + { + movie.PlayController(pad_status, device_number); + movie.InputUpdate(); + } + else if (movie.IsRecordingInput()) + { + movie.RecordInput(pad_status, device_number); + movie.InputUpdate(); + } + else + { + movie.CheckPadStatus(pad_status, device_number); + } +} + +GCPadStatus CSIDevice_AMBaseboard::GetPadStatus() +{ + GCPadStatus pad_status = {}; + + // For netplay, the local controllers are polled in GetNetPads(), and + // the remote controllers receive their status there as well + if (!NetPlay::IsNetPlayRunning()) + { + pad_status = Pad::GetStatus(m_device_number); + } + + // Our GCAdapter code sets PAD_GET_ORIGIN when a new device has been connected. + // Watch for this to calibrate real controllers on connection. + if (pad_status.button & PAD_GET_ORIGIN) + SetOrigin(pad_status); + + return pad_status; } } // namespace SerialInterface diff --git a/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.h b/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.h index dc79df72a3..e7ca8574e0 100644 --- a/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.h +++ b/Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.h @@ -4,15 +4,18 @@ #pragma once #include -#include -#include -#include -#include -#include +#include #include "Common/CommonTypes.h" #include "Common/Flag.h" +#include "Core/HW/GCPad.h" #include "Core/HW/SI/SI_Device.h" +#include "InputCommon/GCPadStatus.h" + +namespace Movie +{ +class MovieManager; +} namespace SerialInterface { @@ -229,7 +232,7 @@ private: u32 m_fzdx_sensor_left; u8 m_rx_reply; - // F-Zero AX (CryCraft) + // F-Zero AX (CyCraft) u32 m_fzcc_seatbelt; u32 m_fzcc_sensor; u32 m_fzcc_emergency; @@ -237,6 +240,44 @@ private: void ICCardSendReply(ICCommand* iccommand, u8* buffer, u32* length); +protected: + struct SOrigin + { + u16 button; + u8 origin_stick_x; + u8 origin_stick_y; + u8 substick_x; + u8 substick_y; + u8 trigger_left; + u8 trigger_right; + u8 unk_4; + u8 unk_5; + }; + + enum EButtonCombo + { + COMBO_NONE = 0, + COMBO_ORIGIN, + COMBO_RESET + }; + + // struct to compare input against + // Set on connection to perfect neutral values + // (standard pad only) Set on button combo to current input state + SOrigin m_origin = {}; + + // PADAnalogMode + // Dunno if we need to do this, game/lib should set it? + u8 m_mode = 0x3; + + // Timer to track special button combos: + // y, X, start for 3 seconds updates origin with current status + // Technically, the above is only on standard pad, wavebird does not support it for example + // b, x, start for 3 seconds triggers reset (PI reset button interrupt) + u64 m_timer_button_combo_start = 0; + // Type of button combo from the last/current poll + EButtonCombo m_last_button_combo = COMBO_NONE; + public: // constructor CSIDevice_AMBaseboard(Core::System& system, SIDevices device, int device_number); @@ -249,6 +290,20 @@ public: // send a command directly void SendCommand(u32 command, u8 poll) override; + + virtual GCPadStatus GetPadStatus(); + virtual u32 MapPadStatus(const GCPadStatus& pad_status); + virtual EButtonCombo HandleButtonCombos(const GCPadStatus& pad_status); + + static void HandleMoviePadStatus(Movie::MovieManager& movie, int device_number, + GCPadStatus* pad_status); + + // Send and Receive pad input from network + static bool NetPlay_GetInput(int pad_num, GCPadStatus* status); + static int NetPlay_InGamePadToLocalPad(int pad_num); + +protected: + void SetOrigin(const GCPadStatus& pad_status); }; } // namespace SerialInterface diff --git a/Source/Core/Core/HW/SI/SI_DeviceGCController.h b/Source/Core/Core/HW/SI/SI_DeviceGCController.h index 19b5bdb14b..f4dc5768c9 100644 --- a/Source/Core/Core/HW/SI/SI_DeviceGCController.h +++ b/Source/Core/Core/HW/SI/SI_DeviceGCController.h @@ -3,8 +3,11 @@ #pragma once +#include #include +#include "Common/CommonTypes.h" +#include "Common/Flag.h" #include "Core/HW/GCPad.h" #include "Core/HW/SI/SI_Device.h" #include "InputCommon/GCPadStatus.h" diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index 3f4344ad88..bfda17a715 100644 --- a/Source/Core/Core/NetPlayClient.cpp +++ b/Source/Core/Core/NetPlayClient.cpp @@ -54,6 +54,7 @@ #include "Core/HW/GCPad.h" #include "Core/HW/SI/SI.h" #include "Core/HW/SI/SI_Device.h" +#include "Core/HW/SI/SI_DeviceAMBaseboard.h" #include "Core/HW/SI/SI_DeviceGCController.h" #include "Core/HW/Sram.h" #include "Core/HW/WiiSave.h" @@ -1891,6 +1892,8 @@ void NetPlayClient::UpdateDevices() auto& si = Core::System::GetInstance().GetSerialInterface(); for (auto player_id : m_pad_map) { + const SerialInterface::SIDevices si_device = Config::Get(Config::GetInfoForSIDevice(local_pad)); + if (m_gba_config[pad].enabled && player_id > 0) { si.ChangeDevice(SerialInterface::SIDEVICE_GC_GBA_EMULATED, pad); @@ -1898,8 +1901,6 @@ void NetPlayClient::UpdateDevices() else if (player_id == m_local_player->pid) { // Use local controller types for local controllers if they are compatible - const SerialInterface::SIDevices si_device = - Config::Get(Config::GetInfoForSIDevice(local_pad)); if (SerialInterface::SIDevice_IsGCController(si_device)) { si.ChangeDevice(si_device, pad); @@ -1917,7 +1918,8 @@ void NetPlayClient::UpdateDevices() } else if (player_id > 0) { - si.ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad); + if (si_device != SerialInterface::SIDEVICE_AM_BASEBOARD) + si.ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad); } else { @@ -2780,6 +2782,16 @@ bool SerialInterface::CSIDevice_GCController::NetPlay_GetInput(int pad_num, GCPa return false; } +bool SerialInterface::CSIDevice_AMBaseboard::NetPlay_GetInput(int pad_num, GCPadStatus* status) +{ + std::lock_guard lk(NetPlay::crit_netplay_client); + + if (NetPlay::netplay_client) + return NetPlay::netplay_client->GetNetPads(pad_num, NetPlay::s_si_poll_batching, status); + + return false; +} + bool NetPlay::NetPlay_GetWiimoteData(const std::span& entries) { std::lock_guard lk(crit_netplay_client); @@ -2852,3 +2864,12 @@ int SerialInterface::CSIDevice_GCController::NetPlay_InGamePadToLocalPad(int num return numPAD; } +int SerialInterface::CSIDevice_AMBaseboard::NetPlay_InGamePadToLocalPad(int numPAD) +{ + std::lock_guard lk(NetPlay::crit_netplay_client); + + if (NetPlay::netplay_client) + return NetPlay::netplay_client->InGamePadToLocalPad(numPAD); + + return numPAD; +}