@@ -3,6 +3,8 @@

#pragma once

#include <array>

#include "Core/HW/GCPad.h"
#include "Core/HW/SI/SI_Device.h"
#include "InputCommon/GCPadStatus.h"
@@ -52,6 +54,7 @@ class CSIDevice_GCController : public ISIDevice
public:
// Constructor
CSIDevice_GCController(SIDevices device, int device_number);
~CSIDevice_GCController() override;

// Run the SI Buffer
int RunBuffer(u8* buffer, int request_length) override;
@@ -74,12 +77,18 @@ class CSIDevice_GCController : public ISIDevice
static int NetPlay_InGamePadToLocalPad(int pad_num);

// Direct rumble to the right GC Controller
static void Rumble(int pad_num, ControlState strength);
static void Rumble(int pad_num, ControlState strength, SIDevices device);

static void HandleMoviePadStatus(int device_number, GCPadStatus* pad_status);

protected:
void SetOrigin(const GCPadStatus& pad_status);

private:
void RefreshConfig();

std::array<SIDevices, 4> m_config_si_devices{};
size_t m_config_changed_callback_id;
};

// "TaruKonga", the DK Bongo controller
@@ -453,9 +453,10 @@ void ChangePads()

for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
{
if (SConfig::GetInstance().m_SIDevice[i] == SerialInterface::SIDEVICE_GC_GBA_EMULATED)
const SerialInterface::SIDevices si_device = Config::Get(Config::GetInfoForSIDevice(i));
if (si_device == SerialInterface::SIDEVICE_GC_GBA_EMULATED)
controllers[i] = ControllerType::GBA;
else if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i]))
else if (SerialInterface::SIDevice_IsGCController(si_device))
controllers[i] = ControllerType::GC;
else
controllers[i] = ControllerType::None;
@@ -473,9 +474,10 @@ void ChangePads()
}
else if (IsUsingPad(i))
{
if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i]))
const SerialInterface::SIDevices si_device = Config::Get(Config::GetInfoForSIDevice(i));
if (SerialInterface::SIDevice_IsGCController(si_device))
{
device = SConfig::GetInstance().m_SIDevice[i];
device = si_device;
}
else
{
@@ -548,7 +550,8 @@ bool BeginRecordingInput(const ControllerTypeArray& controllers,

for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
{
if (SConfig::GetInstance().m_SIDevice[i] == SerialInterface::SIDEVICE_GC_TARUKONGA)
const SerialInterface::SIDevices si_device = Config::Get(Config::GetInfoForSIDevice(i));
if (si_device == SerialInterface::SIDEVICE_GC_TARUKONGA)
s_bongos |= (1 << i);
}

@@ -1435,14 +1438,12 @@ void SetGraphicsConfig()
// NOTE: EmuThread / Host Thread
void GetSettings()
{
const bool slot_a_has_raw_memcard =
SConfig::GetInstance().m_EXIDevice[0] == ExpansionInterface::EXIDEVICE_MEMORYCARD;
const bool slot_a_has_gci_folder =
SConfig::GetInstance().m_EXIDevice[0] == ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER;
const bool slot_b_has_raw_memcard =
SConfig::GetInstance().m_EXIDevice[1] == ExpansionInterface::EXIDEVICE_MEMORYCARD;
const bool slot_b_has_gci_folder =
SConfig::GetInstance().m_EXIDevice[1] == ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER;
const ExpansionInterface::TEXIDevices slot_a_type = Config::Get(Config::MAIN_SLOT_A);
const ExpansionInterface::TEXIDevices slot_b_type = Config::Get(Config::MAIN_SLOT_B);
const bool slot_a_has_raw_memcard = slot_a_type == ExpansionInterface::EXIDEVICE_MEMORYCARD;
const bool slot_a_has_gci_folder = slot_a_type == ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER;
const bool slot_b_has_raw_memcard = slot_b_type == ExpansionInterface::EXIDEVICE_MEMORYCARD;
const bool slot_b_has_gci_folder = slot_b_type == ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER;

s_bSaveConfig = true;
s_bNetPlay = NetPlay::IsNetPlayRunning();
@@ -1838,11 +1838,13 @@ void NetPlayClient::UpdateDevices()
else if (player_id == m_local_player->pid)
{
// Use local controller types for local controllers if they are compatible
if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[local_pad]))
const SerialInterface::SIDevices si_device =
Config::Get(Config::GetInfoForSIDevice(local_pad));
if (SerialInterface::SIDevice_IsGCController(si_device))
{
SerialInterface::ChangeDevice(SConfig::GetInstance().m_SIDevice[local_pad], pad);
SerialInterface::ChangeDevice(si_device, pad);

if (SConfig::GetInstance().m_SIDevice[local_pad] == SerialInterface::SIDEVICE_WIIU_ADAPTER)
if (si_device == SerialInterface::SIDEVICE_WIIU_ADAPTER)
{
GCAdapter::ResetDeviceType(local_pad);
}
@@ -2161,7 +2163,8 @@ bool NetPlayClient::PollLocalPad(const int local_pad, sf::Packet& packet)
{
pad_status = Pad::GetGBAStatus(local_pad);
}
else if (SConfig::GetInstance().m_SIDevice[local_pad] == SerialInterface::SIDEVICE_WIIU_ADAPTER)
else if (Config::Get(Config::GetInfoForSIDevice(local_pad)) ==
SerialInterface::SIDEVICE_WIIU_ADAPTER)
{
pad_status = GCAdapter::Input(local_pad);
}
@@ -1307,10 +1307,8 @@ bool NetPlayServer::SetupNetSettings()
settings.m_CopyWiiSave = Config::Get(Config::NETPLAY_LOAD_WII_SAVE);
settings.m_OCEnable = Config::Get(Config::MAIN_OVERCLOCK_ENABLE);
settings.m_OCFactor = Config::Get(Config::MAIN_OVERCLOCK);
settings.m_EXIDevice[0] =
static_cast<ExpansionInterface::TEXIDevices>(Config::Get(Config::MAIN_SLOT_A));
settings.m_EXIDevice[1] =
static_cast<ExpansionInterface::TEXIDevices>(Config::Get(Config::MAIN_SLOT_B));
settings.m_EXIDevice[0] = Config::Get(Config::MAIN_SLOT_A);
settings.m_EXIDevice[1] = Config::Get(Config::MAIN_SLOT_B);
// There's no way the BBA is going to sync, disable it
settings.m_EXIDevice[2] = ExpansionInterface::EXIDEVICE_NONE;

@@ -1595,11 +1593,12 @@ bool NetPlayServer::SyncSaveData()

u8 save_count = 0;

constexpr size_t exi_device_count = 2;
for (size_t i = 0; i < exi_device_count; i++)
constexpr int exi_device_count = 2;
for (int i = 0; i < exi_device_count; ++i)
{
if (m_settings.m_EXIDevice[i] == ExpansionInterface::EXIDEVICE_MEMORYCARD ||
SConfig::GetInstance().m_EXIDevice[i] == ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER)
Config::Get(Config::GetInfoForEXIDevice(i)) ==
ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER)
{
save_count++;
}
@@ -1654,7 +1653,7 @@ bool NetPlayServer::SyncSaveData()
const std::string region =
SConfig::GetDirectoryForRegion(SConfig::ToGameCubeRegion(game->GetRegion()));

for (size_t i = 0; i < exi_device_count; i++)
for (int i = 0; i < exi_device_count; ++i)
{
const bool is_slot_a = i == 0;

@@ -1695,7 +1694,7 @@ bool NetPlayServer::SyncSaveData()
SendChunkedToClients(std::move(pac), 1,
fmt::format("Memory Card {} Synchronization", is_slot_a ? 'A' : 'B'));
}
else if (SConfig::GetInstance().m_EXIDevice[i] ==
else if (Config::Get(Config::GetInfoForEXIDevice(i)) ==
ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER)
{
const std::string path = File::GetUserPath(D_GCUSER_IDX) + region + DIR_SEP +
@@ -178,7 +178,8 @@ void GamecubeControllersWidget::LoadSettings()
{
for (size_t i = 0; i < m_gc_groups.size(); i++)
{
const SerialInterface::SIDevices si_device = SConfig::GetInstance().m_SIDevice[i];
const SerialInterface::SIDevices si_device =
Config::Get(Config::GetInfoForSIDevice(static_cast<int>(i)));
const std::optional<int> gc_index = ToGCMenuIndex(si_device);
if (gc_index)
{
@@ -194,7 +195,7 @@ void GamecubeControllersWidget::SaveSettings()
{
const int index = m_gc_controller_boxes[i]->currentIndex();
const SerialInterface::SIDevices si_device = FromGCMenuIndex(index);
SConfig::GetInstance().m_SIDevice[i] = si_device;
Config::SetBaseOrCurrent(Config::GetInfoForSIDevice(static_cast<int>(i)), si_device);

if (Core::IsRunning())
SerialInterface::ChangeDevice(si_device, static_cast<s32>(i));
@@ -664,7 +664,9 @@ void GameList::OpenGCSaveFolder()
for (int i = 0; i < 2; i++)
{
QUrl url;
switch (SConfig::GetInstance().m_EXIDevice[i])
const ExpansionInterface::TEXIDevices current_exi_device =
Config::Get(Config::GetInfoForEXIDevice(i));
switch (current_exi_device)
{
case ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER:
{
@@ -1728,9 +1728,10 @@ void MainWindow::OnStartRecording()

for (int i = 0; i < 4; i++)
{
if (SConfig::GetInstance().m_SIDevice[i] == SerialInterface::SIDEVICE_GC_GBA_EMULATED)
const SerialInterface::SIDevices si_device = Config::Get(Config::GetInfoForSIDevice(i));
if (si_device == SerialInterface::SIDEVICE_GC_GBA_EMULATED)
controllers[i] = Movie::ControllerType::GBA;
else if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i]))
else if (SerialInterface::SIDevice_IsGCController(si_device))
controllers[i] = Movie::ControllerType::GC;
else
controllers[i] = Movie::ControllerType::None;
@@ -1782,8 +1783,9 @@ void MainWindow::ShowTASInput()
{
for (int i = 0; i < num_gc_controllers; i++)
{
if (SConfig::GetInstance().m_SIDevice[i] != SerialInterface::SIDEVICE_NONE &&
SConfig::GetInstance().m_SIDevice[i] != SerialInterface::SIDEVICE_GC_GBA)
const auto si_device = Config::Get(Config::GetInfoForSIDevice(i));
if (si_device != SerialInterface::SIDEVICE_NONE &&
si_device != SerialInterface::SIDEVICE_GC_GBA)
{
m_gc_tas_input_windows[i]->show();
m_gc_tas_input_windows[i]->raise();
@@ -458,8 +458,8 @@ void GameCubePane::LoadSettings()
for (int i = 0; i < SLOT_COUNT; i++)
{
QSignalBlocker blocker(m_slot_combos[i]);
m_slot_combos[i]->setCurrentIndex(
m_slot_combos[i]->findData(SConfig::GetInstance().m_EXIDevice[i]));
const ExpansionInterface::TEXIDevices exi_device = Config::Get(Config::GetInfoForEXIDevice(i));
m_slot_combos[i]->setCurrentIndex(m_slot_combos[i]->findData(exi_device));
UpdateButton(i);
}

@@ -486,8 +486,10 @@ void GameCubePane::SaveSettings()
for (int i = 0; i < SLOT_COUNT; i++)
{
const auto dev = ExpansionInterface::TEXIDevices(m_slot_combos[i]->currentData().toInt());
const ExpansionInterface::TEXIDevices current_exi_device =
Config::Get(Config::GetInfoForEXIDevice(i));

if (Core::IsRunning() && SConfig::GetInstance().m_EXIDevice[i] != dev)
if (Core::IsRunning() && current_exi_device != dev)
{
ExpansionInterface::ChangeDevice(
// SlotB is on channel 1, slotA and SP1 are on 0
@@ -498,19 +500,7 @@ void GameCubePane::SaveSettings()
(i == 2) ? 2 : 0);
}

SConfig::GetInstance().m_EXIDevice[i] = dev;
switch (i)
{
case SLOT_A_INDEX:
Config::SetBaseOrCurrent(Config::MAIN_SLOT_A, dev);
break;
case SLOT_B_INDEX:
Config::SetBaseOrCurrent(Config::MAIN_SLOT_B, dev);
break;
case SLOT_SP1_INDEX:
Config::SetBaseOrCurrent(Config::MAIN_SERIAL_PORT_1, dev);
break;
}
Config::SetBaseOrCurrent(Config::GetInfoForEXIDevice(i), dev);
}

#ifdef HAS_LIBMGBA
@@ -83,6 +83,8 @@ static u8 s_endpoint_out = 0;
static u64 s_last_init = 0;

static std::optional<size_t> s_config_callback_id = std::nullopt;
static std::array<SerialInterface::SIDevices, SerialInterface::MAX_SI_CHANNELS>
s_config_si_device_type{};
static std::array<bool, SerialInterface::MAX_SI_CHANNELS> s_config_rumble_enabled{};

static void Read()
@@ -205,7 +207,10 @@ void SetAdapterCallback(std::function<void()> func)
static void RefreshConfig()
{
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
{
s_config_si_device_type[i] = Config::Get(Config::GetInfoForSIDevice(i));
s_config_rumble_enabled[i] = Config::Get(Config::GetInfoForAdapterRumble(i));
}
}

void Init()
@@ -542,9 +547,8 @@ void ResetDeviceType(int chan)

bool UseAdapter()
{
const auto& si_devices = SConfig::GetInstance().m_SIDevice;

return std::any_of(std::begin(si_devices), std::end(si_devices), [](const auto device_type) {
const auto& si_devices = s_config_si_device_type;
return std::any_of(si_devices.begin(), si_devices.end(), [](const auto device_type) {
return device_type == SerialInterface::SIDEVICE_WIIU_ADAPTER;
});
}
@@ -12,7 +12,7 @@
#include "Common/Flag.h"
#include "Common/Logging/Log.h"
#include "Common/Thread.h"
#include "Core/ConfigManager.h"
#include "Core/Config/MainSettings.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/HW/SI/SI.h"
@@ -61,6 +61,16 @@ static Common::Flag s_adapter_detect_thread_running;

static u64 s_last_init = 0;

static std::optional<size_t> s_config_callback_id = std::nullopt;
static std::array<SerialInterface::SIDevices, SerialInterface::MAX_SI_CHANNELS>
s_config_si_device_type{};

static void RefreshConfig()
{
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
s_config_si_device_type[i] = Config::Get(Config::GetInfoForSIDevice(i));
}

static void ScanThreadFunc()
{
Common::SetCurrentThreadName("GC Adapter Scanning Thread");
@@ -200,6 +210,10 @@ void Init()
jclass adapter_class = env->FindClass("org/dolphinemu/dolphinemu/utils/Java_GCAdapter");
s_adapter_class = reinterpret_cast<jclass>(env->NewGlobalRef(adapter_class));

if (!s_config_callback_id)
s_config_callback_id = Config::AddConfigChangedCallback(RefreshConfig);
RefreshConfig();

if (UseAdapter())
StartScanThread();
}
@@ -236,6 +250,12 @@ void Shutdown()
{
StopScanThread();
Reset();

if (s_config_callback_id)
{
Config::RemoveConfigChangedCallback(*s_config_callback_id);
s_config_callback_id = std::nullopt;
}
}

void StartScanThread()
@@ -376,8 +396,7 @@ void ResetDeviceType(int chan)

bool UseAdapter()
{
const auto& si_devices = SConfig::GetInstance().m_SIDevice;

const auto& si_devices = s_config_si_device_type;
return std::any_of(std::begin(si_devices), std::end(si_devices), [](const auto device_type) {
return device_type == SerialInterface::SIDEVICE_WIIU_ADAPTER;
});