mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-21 05:09:34 -06:00
NetPlay: GBA Support
This commit is contained in:
@ -122,6 +122,7 @@
|
|||||||
#define GC_MEMCARD_NETPLAY "NetPlayTemp"
|
#define GC_MEMCARD_NETPLAY "NetPlayTemp"
|
||||||
|
|
||||||
#define GBA_BIOS "gba_bios.bin"
|
#define GBA_BIOS "gba_bios.bin"
|
||||||
|
#define GBA_SAVE_NETPLAY "NetPlayTemp"
|
||||||
|
|
||||||
#define WII_STATE "state.dat"
|
#define WII_STATE "state.dat"
|
||||||
|
|
||||||
|
@ -57,5 +57,6 @@ const Info<std::string> NETPLAY_NETWORK_MODE{{System::Main, "NetPlay", "NetworkM
|
|||||||
"fixeddelay"};
|
"fixeddelay"};
|
||||||
const Info<bool> NETPLAY_SYNC_ALL_WII_SAVES{{System::Main, "NetPlay", "SyncAllWiiSaves"}, false};
|
const Info<bool> NETPLAY_SYNC_ALL_WII_SAVES{{System::Main, "NetPlay", "SyncAllWiiSaves"}, false};
|
||||||
const Info<bool> NETPLAY_GOLF_MODE_OVERLAY{{System::Main, "NetPlay", "GolfModeOverlay"}, true};
|
const Info<bool> NETPLAY_GOLF_MODE_OVERLAY{{System::Main, "NetPlay", "GolfModeOverlay"}, true};
|
||||||
|
const Info<bool> NETPLAY_HIDE_REMOTE_GBAS{{System::Main, "NetPlay", "HideRemoteGBAs"}, false};
|
||||||
|
|
||||||
} // namespace Config
|
} // namespace Config
|
||||||
|
@ -50,5 +50,6 @@ extern const Info<bool> NETPLAY_STRICT_SETTINGS_SYNC;
|
|||||||
extern const Info<std::string> NETPLAY_NETWORK_MODE;
|
extern const Info<std::string> NETPLAY_NETWORK_MODE;
|
||||||
extern const Info<bool> NETPLAY_SYNC_ALL_WII_SAVES;
|
extern const Info<bool> NETPLAY_SYNC_ALL_WII_SAVES;
|
||||||
extern const Info<bool> NETPLAY_GOLF_MODE_OVERLAY;
|
extern const Info<bool> NETPLAY_GOLF_MODE_OVERLAY;
|
||||||
|
extern const Info<bool> NETPLAY_HIDE_REMOTE_GBAS;
|
||||||
|
|
||||||
} // namespace Config
|
} // namespace Config
|
||||||
|
@ -133,6 +133,11 @@ public:
|
|||||||
layer->Set(Config::SESSION_GCI_FOLDER_CURRENT_GAME_ONLY, true);
|
layer->Set(Config::SESSION_GCI_FOLDER_CURRENT_GAME_ONLY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_settings.m_GBARomPaths.size(); ++i)
|
||||||
|
{
|
||||||
|
layer->Set(Config::MAIN_GBA_ROM_PATHS[i], m_settings.m_GBARomPaths[i]);
|
||||||
|
}
|
||||||
|
|
||||||
// Check To Override Client's Cheat Codes
|
// Check To Override Client's Cheat Codes
|
||||||
if (m_settings.m_SyncCodes && !m_settings.m_IsHosting)
|
if (m_settings.m_SyncCodes && !m_settings.m_IsHosting)
|
||||||
{
|
{
|
||||||
|
@ -219,7 +219,8 @@ bool Core::Start(u64 gc_ticks)
|
|||||||
m_core->getGameTitle(m_core, game_title.data());
|
m_core->getGameTitle(m_core, game_title.data());
|
||||||
m_game_title = game_title.data();
|
m_game_title = game_title.data();
|
||||||
|
|
||||||
m_save_path = GetSavePath(m_rom_path, m_device_number);
|
m_save_path = NetPlay::IsNetPlayRunning() ? NetPlay::GetGBASavePath(m_device_number) :
|
||||||
|
GetSavePath(m_rom_path, m_device_number);
|
||||||
if (!m_save_path.empty() && !LoadSave(m_save_path.c_str()))
|
if (!m_save_path.empty() && !LoadSave(m_save_path.c_str()))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -33,12 +33,18 @@
|
|||||||
#include "Common/Version.h"
|
#include "Common/Version.h"
|
||||||
|
|
||||||
#include "Core/ActionReplay.h"
|
#include "Core/ActionReplay.h"
|
||||||
|
#include "Core/Config/MainSettings.h"
|
||||||
#include "Core/Config/NetplaySettings.h"
|
#include "Core/Config/NetplaySettings.h"
|
||||||
#include "Core/Config/SessionSettings.h"
|
#include "Core/Config/SessionSettings.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/GeckoCode.h"
|
#include "Core/GeckoCode.h"
|
||||||
#include "Core/HW/EXI/EXI_DeviceIPL.h"
|
#include "Core/HW/EXI/EXI_DeviceIPL.h"
|
||||||
|
#ifdef HAS_LIBMGBA
|
||||||
|
#include "Core/HW/GBACore.h"
|
||||||
|
#endif
|
||||||
|
#include "Core/HW/GBAPad.h"
|
||||||
#include "Core/HW/GCMemcard/GCMemcard.h"
|
#include "Core/HW/GCMemcard/GCMemcard.h"
|
||||||
|
#include "Core/HW/GCPad.h"
|
||||||
#include "Core/HW/SI/SI.h"
|
#include "Core/HW/SI/SI.h"
|
||||||
#include "Core/HW/SI/SI_Device.h"
|
#include "Core/HW/SI/SI_Device.h"
|
||||||
#include "Core/HW/SI/SI_DeviceGCController.h"
|
#include "Core/HW/SI/SI_DeviceGCController.h"
|
||||||
@ -71,7 +77,7 @@ static std::mutex crit_netplay_client;
|
|||||||
static NetPlayClient* netplay_client = nullptr;
|
static NetPlayClient* netplay_client = nullptr;
|
||||||
static std::unique_ptr<IOS::HLE::FS::FileSystem> s_wii_sync_fs;
|
static std::unique_ptr<IOS::HLE::FS::FileSystem> s_wii_sync_fs;
|
||||||
static std::vector<u64> s_wii_sync_titles;
|
static std::vector<u64> s_wii_sync_titles;
|
||||||
static bool s_si_poll_batching;
|
static bool s_si_poll_batching = false;
|
||||||
|
|
||||||
// called from ---GUI--- thread
|
// called from ---GUI--- thread
|
||||||
NetPlayClient::~NetPlayClient()
|
NetPlayClient::~NetPlayClient()
|
||||||
@ -463,6 +469,35 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NP_MSG_GBA_CONFIG:
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < m_gba_config.size(); ++i)
|
||||||
|
{
|
||||||
|
auto& config = m_gba_config[i];
|
||||||
|
const auto old_config = config;
|
||||||
|
|
||||||
|
packet >> config.enabled >> config.has_rom >> config.title;
|
||||||
|
for (auto& data : config.hash)
|
||||||
|
packet >> data;
|
||||||
|
|
||||||
|
if (std::tie(config.has_rom, config.title, config.hash) !=
|
||||||
|
std::tie(old_config.has_rom, old_config.title, old_config.hash))
|
||||||
|
{
|
||||||
|
m_dialog->OnMsgChangeGBARom(static_cast<int>(i), config);
|
||||||
|
m_net_settings.m_GBARomPaths[i] =
|
||||||
|
config.has_rom ?
|
||||||
|
m_dialog->FindGBARomPath(config.hash, config.title, static_cast<int>(i)) :
|
||||||
|
"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SendGameStatus();
|
||||||
|
UpdateDevices();
|
||||||
|
|
||||||
|
m_dialog->Update();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case NP_MSG_WIIMOTE_MAPPING:
|
case NP_MSG_WIIMOTE_MAPPING:
|
||||||
{
|
{
|
||||||
for (PlayerId& mapping : m_wiimote_map)
|
for (PlayerId& mapping : m_wiimote_map)
|
||||||
@ -482,8 +517,12 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
|||||||
packet >> map;
|
packet >> map;
|
||||||
|
|
||||||
GCPadStatus pad;
|
GCPadStatus pad;
|
||||||
packet >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >>
|
packet >> pad.button;
|
||||||
pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
if (!m_gba_config.at(map).enabled)
|
||||||
|
{
|
||||||
|
packet >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >> pad.substickX >>
|
||||||
|
pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
||||||
|
}
|
||||||
|
|
||||||
// Trusting server for good map value (>=0 && <4)
|
// Trusting server for good map value (>=0 && <4)
|
||||||
// add to pad buffer
|
// add to pad buffer
|
||||||
@ -501,8 +540,12 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
|||||||
packet >> map;
|
packet >> map;
|
||||||
|
|
||||||
GCPadStatus pad;
|
GCPadStatus pad;
|
||||||
packet >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >>
|
packet >> pad.button;
|
||||||
pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
if (!m_gba_config.at(map).enabled)
|
||||||
|
{
|
||||||
|
packet >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >> pad.substickX >>
|
||||||
|
pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
||||||
|
}
|
||||||
|
|
||||||
// Trusting server for good map value (>=0 && <4)
|
// Trusting server for good map value (>=0 && <4)
|
||||||
// write to last status
|
// write to last status
|
||||||
@ -602,14 +645,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
|||||||
// update gui
|
// update gui
|
||||||
m_dialog->OnMsgChangeGame(m_selected_game, netplay_name);
|
m_dialog->OnMsgChangeGame(m_selected_game, netplay_name);
|
||||||
|
|
||||||
sf::Packet game_status_packet;
|
SendGameStatus();
|
||||||
game_status_packet << static_cast<MessageId>(NP_MSG_GAME_STATUS);
|
|
||||||
|
|
||||||
SyncIdentifierComparison result;
|
|
||||||
m_dialog->FindGameFile(m_selected_game, &result);
|
|
||||||
|
|
||||||
game_status_packet << static_cast<u32>(result);
|
|
||||||
Send(game_status_packet);
|
|
||||||
|
|
||||||
sf::Packet client_capabilities_packet;
|
sf::Packet client_capabilities_packet;
|
||||||
client_capabilities_packet << static_cast<MessageId>(NP_MSG_CLIENT_CAPABILITIES);
|
client_capabilities_packet << static_cast<MessageId>(NP_MSG_CLIENT_CAPABILITIES);
|
||||||
@ -739,6 +775,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
|||||||
|
|
||||||
packet >> m_net_settings.m_GolfMode;
|
packet >> m_net_settings.m_GolfMode;
|
||||||
packet >> m_net_settings.m_UseFMA;
|
packet >> m_net_settings.m_UseFMA;
|
||||||
|
packet >> m_net_settings.m_HideRemoteGBAs;
|
||||||
|
|
||||||
m_net_settings.m_IsHosting = m_local_player->IsHost();
|
m_net_settings.m_IsHosting = m_local_player->IsHost();
|
||||||
m_net_settings.m_HostInputAuthority = m_host_input_authority;
|
m_net_settings.m_HostInputAuthority = m_host_input_authority;
|
||||||
@ -1055,6 +1092,29 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SYNC_SAVE_DATA_GBA:
|
||||||
|
{
|
||||||
|
if (m_local_player->IsHost())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u8 slot;
|
||||||
|
packet >> slot;
|
||||||
|
|
||||||
|
const std::string path =
|
||||||
|
fmt::format("{}{}{}.sav", File::GetUserPath(D_GBAUSER_IDX), GBA_SAVE_NETPLAY, slot + 1);
|
||||||
|
if (File::Exists(path) && !File::Delete(path))
|
||||||
|
{
|
||||||
|
PanicAlertFmtT("Failed to delete NetPlay GBA{0} save file. Verify your write permissions.",
|
||||||
|
slot + 1);
|
||||||
|
SyncSaveDataResponse(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool success = DecompressPacketIntoFile(packet, path);
|
||||||
|
SyncSaveDataResponse(success);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PanicAlertFmtT("Unknown SYNC_SAVE_DATA message received with id: {0}", sub_id);
|
PanicAlertFmtT("Unknown SYNC_SAVE_DATA message received with id: {0}", sub_id);
|
||||||
break;
|
break;
|
||||||
@ -1411,26 +1471,13 @@ void NetPlayClient::GetPlayerList(std::string& list, std::vector<int>& pid_list)
|
|||||||
|
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
|
|
||||||
const auto enumerate_player_controller_mappings = [&ss](const PadMappingArray& mappings,
|
|
||||||
const Player& player) {
|
|
||||||
for (size_t i = 0; i < mappings.size(); i++)
|
|
||||||
{
|
|
||||||
if (mappings[i] == player.pid)
|
|
||||||
ss << i + 1;
|
|
||||||
else
|
|
||||||
ss << '-';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const auto& entry : m_players)
|
for (const auto& entry : m_players)
|
||||||
{
|
{
|
||||||
const Player& player = entry.second;
|
const Player& player = entry.second;
|
||||||
ss << player.name << "[" << static_cast<int>(player.pid) << "] : " << player.revision << " | ";
|
ss << player.name << "[" << static_cast<int>(player.pid) << "] : " << player.revision << " | "
|
||||||
|
<< GetPlayerMappingString(player.pid, m_pad_map, m_gba_config, m_wiimote_map) << " |\n";
|
||||||
|
|
||||||
enumerate_player_controller_mappings(m_pad_map, player);
|
ss << "Ping: " << player.ping << "ms\n";
|
||||||
enumerate_player_controller_mappings(m_wiimote_map, player);
|
|
||||||
|
|
||||||
ss << " |\nPing: " << player.ping << "ms\n";
|
|
||||||
ss << "Status: ";
|
ss << "Status: ";
|
||||||
|
|
||||||
switch (player.game_status)
|
switch (player.game_status)
|
||||||
@ -1492,8 +1539,12 @@ void NetPlayClient::AddPadStateToPacket(const int in_game_pad, const GCPadStatus
|
|||||||
sf::Packet& packet)
|
sf::Packet& packet)
|
||||||
{
|
{
|
||||||
packet << static_cast<PadIndex>(in_game_pad);
|
packet << static_cast<PadIndex>(in_game_pad);
|
||||||
packet << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX
|
packet << pad.button;
|
||||||
<< pad.substickY << pad.triggerLeft << pad.triggerRight << pad.isConnected;
|
if (!m_gba_config[in_game_pad].enabled)
|
||||||
|
{
|
||||||
|
packet << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX
|
||||||
|
<< pad.substickY << pad.triggerLeft << pad.triggerRight << pad.isConnected;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from ---CPU--- thread
|
// called from ---CPU--- thread
|
||||||
@ -1648,11 +1699,13 @@ void NetPlayClient::UpdateDevices()
|
|||||||
|
|
||||||
for (auto player_id : m_pad_map)
|
for (auto player_id : m_pad_map)
|
||||||
{
|
{
|
||||||
// Use local controller types for local controllers if they are compatible
|
if (m_gba_config[pad].enabled && player_id > 0)
|
||||||
// Only GCController-like controllers are supported, GBA and similar
|
|
||||||
// exotic devices are not supported on netplay.
|
|
||||||
if (player_id == m_local_player->pid)
|
|
||||||
{
|
{
|
||||||
|
SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_GC_GBA_EMULATED, pad);
|
||||||
|
}
|
||||||
|
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]))
|
if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[local_pad]))
|
||||||
{
|
{
|
||||||
SerialInterface::ChangeDevice(SConfig::GetInstance().m_SIDevice[local_pad], pad);
|
SerialInterface::ChangeDevice(SConfig::GetInstance().m_SIDevice[local_pad], pad);
|
||||||
@ -1968,21 +2021,22 @@ bool NetPlayClient::WiimoteUpdate(int _number, u8* data, const std::size_t size,
|
|||||||
|
|
||||||
bool NetPlayClient::PollLocalPad(const int local_pad, sf::Packet& packet)
|
bool NetPlayClient::PollLocalPad(const int local_pad, sf::Packet& packet)
|
||||||
{
|
{
|
||||||
GCPadStatus pad_status;
|
|
||||||
|
|
||||||
switch (SConfig::GetInstance().m_SIDevice[local_pad])
|
|
||||||
{
|
|
||||||
case SerialInterface::SIDEVICE_WIIU_ADAPTER:
|
|
||||||
pad_status = GCAdapter::Input(local_pad);
|
|
||||||
break;
|
|
||||||
case SerialInterface::SIDEVICE_GC_CONTROLLER:
|
|
||||||
default:
|
|
||||||
pad_status = Pad::GetStatus(local_pad);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int ingame_pad = LocalPadToInGamePad(local_pad);
|
const int ingame_pad = LocalPadToInGamePad(local_pad);
|
||||||
bool data_added = false;
|
bool data_added = false;
|
||||||
|
GCPadStatus pad_status;
|
||||||
|
|
||||||
|
if (m_gba_config[ingame_pad].enabled)
|
||||||
|
{
|
||||||
|
pad_status = Pad::GetGBAStatus(local_pad);
|
||||||
|
}
|
||||||
|
else if (SConfig::GetInstance().m_SIDevice[local_pad] == SerialInterface::SIDEVICE_WIIU_ADAPTER)
|
||||||
|
{
|
||||||
|
pad_status = GCAdapter::Input(local_pad);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pad_status = Pad::GetStatus(local_pad);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_host_input_authority)
|
if (m_host_input_authority)
|
||||||
{
|
{
|
||||||
@ -2234,6 +2288,26 @@ bool NetPlayClient::IsLocalPlayer(const PlayerId pid) const
|
|||||||
return pid == m_local_player->pid;
|
return pid == m_local_player->pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetPlayClient::SendGameStatus()
|
||||||
|
{
|
||||||
|
sf::Packet packet;
|
||||||
|
packet << static_cast<MessageId>(NP_MSG_GAME_STATUS);
|
||||||
|
|
||||||
|
SyncIdentifierComparison result;
|
||||||
|
m_dialog->FindGameFile(m_selected_game, &result);
|
||||||
|
for (size_t i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
if (m_gba_config[i].enabled && m_gba_config[i].has_rom &&
|
||||||
|
m_net_settings.m_GBARomPaths[i].empty())
|
||||||
|
{
|
||||||
|
result = SyncIdentifierComparison::DifferentGame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
packet << static_cast<u32>(result);
|
||||||
|
Send(packet);
|
||||||
|
}
|
||||||
|
|
||||||
void NetPlayClient::SendTimeBase()
|
void NetPlayClient::SendTimeBase()
|
||||||
{
|
{
|
||||||
std::lock_guard lk(crit_netplay_client);
|
std::lock_guard lk(crit_netplay_client);
|
||||||
@ -2309,6 +2383,11 @@ const PadMappingArray& NetPlayClient::GetPadMapping() const
|
|||||||
return m_pad_map;
|
return m_pad_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GBAConfigArray& NetPlayClient::GetGBAConfig() const
|
||||||
|
{
|
||||||
|
return m_gba_config;
|
||||||
|
}
|
||||||
|
|
||||||
const PadMappingArray& NetPlayClient::GetWiimoteMapping() const
|
const PadMappingArray& NetPlayClient::GetWiimoteMapping() const
|
||||||
{
|
{
|
||||||
return m_wiimote_map;
|
return m_wiimote_map;
|
||||||
@ -2325,6 +2404,32 @@ SyncIdentifier NetPlayClient::GetSDCardIdentifier()
|
|||||||
return SyncIdentifier{{}, "sd", {}, {}, {}, {}};
|
return SyncIdentifier{{}, "sd", {}, {}, {}, {}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetPlayerMappingString(PlayerId pid, const PadMappingArray& pad_map,
|
||||||
|
const GBAConfigArray& gba_config,
|
||||||
|
const PadMappingArray& wiimote_map)
|
||||||
|
{
|
||||||
|
std::vector<size_t> gc_slots, gba_slots, wiimote_slots;
|
||||||
|
for (size_t i = 0; i < pad_map.size(); ++i)
|
||||||
|
{
|
||||||
|
if (pad_map[i] == pid && !gba_config[i].enabled)
|
||||||
|
gc_slots.push_back(i + 1);
|
||||||
|
if (pad_map[i] == pid && gba_config[i].enabled)
|
||||||
|
gba_slots.push_back(i + 1);
|
||||||
|
if (wiimote_map[i] == pid)
|
||||||
|
wiimote_slots.push_back(i + 1);
|
||||||
|
}
|
||||||
|
std::vector<std::string> groups;
|
||||||
|
for (const auto& [group_name, slots] :
|
||||||
|
{std::make_pair("GC", &gc_slots), std::make_pair("GBA", &gba_slots),
|
||||||
|
std::make_pair("Wii", &wiimote_slots)})
|
||||||
|
{
|
||||||
|
if (!slots->empty())
|
||||||
|
groups.emplace_back(fmt::format("{}{}", group_name, fmt::join(*slots, ",")));
|
||||||
|
}
|
||||||
|
std::string res = fmt::format("{}", fmt::join(groups, "|"));
|
||||||
|
return res.empty() ? "None" : res;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsNetPlayRunning()
|
bool IsNetPlayRunning()
|
||||||
{
|
{
|
||||||
return netplay_client != nullptr;
|
return netplay_client != nullptr;
|
||||||
@ -2401,6 +2506,60 @@ void SetupWiimotes()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetGBASavePath(int pad_num)
|
||||||
|
{
|
||||||
|
std::lock_guard lk(crit_netplay_client);
|
||||||
|
|
||||||
|
if (!netplay_client || NetPlay::GetNetSettings().m_IsHosting)
|
||||||
|
{
|
||||||
|
#ifdef HAS_LIBMGBA
|
||||||
|
std::string rom_path = Config::Get(Config::MAIN_GBA_ROM_PATHS[pad_num]);
|
||||||
|
return HW::GBA::Core::GetSavePath(rom_path, pad_num);
|
||||||
|
#else
|
||||||
|
return {};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NetPlay::GetNetSettings().m_SyncSaveData)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return fmt::format("{}{}{}.sav", File::GetUserPath(D_GBAUSER_IDX), GBA_SAVE_NETPLAY, pad_num + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
PadDetails GetPadDetails(int pad_num)
|
||||||
|
{
|
||||||
|
std::lock_guard lk(crit_netplay_client);
|
||||||
|
|
||||||
|
PadDetails res{.local_pad = 4};
|
||||||
|
if (!netplay_client)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
auto pad_map = netplay_client->GetPadMapping();
|
||||||
|
if (pad_map[pad_num] <= 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
for (auto player : netplay_client->GetPlayers())
|
||||||
|
{
|
||||||
|
if (player->pid == pad_map[pad_num])
|
||||||
|
res.player_name = player->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int local_pad = 0;
|
||||||
|
int non_local_pad = 0;
|
||||||
|
for (int i = 0; i < pad_num; ++i)
|
||||||
|
{
|
||||||
|
if (netplay_client->IsLocalPlayer(pad_map[i]))
|
||||||
|
++local_pad;
|
||||||
|
else
|
||||||
|
++non_local_pad;
|
||||||
|
}
|
||||||
|
res.is_local = netplay_client->IsLocalPlayer(pad_map[pad_num]);
|
||||||
|
res.local_pad = res.is_local ? local_pad : netplay_client->NumLocalPads() + non_local_pad;
|
||||||
|
res.hide_gba = !res.is_local && netplay_client->GetNetSettings().m_HideRemoteGBAs &&
|
||||||
|
netplay_client->LocalPlayerHasControllerMapped();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
void NetPlay_Enable(NetPlayClient* const np)
|
void NetPlay_Enable(NetPlayClient* const np)
|
||||||
{
|
{
|
||||||
std::lock_guard lk(crit_netplay_client);
|
std::lock_guard lk(crit_netplay_client);
|
||||||
|
@ -43,6 +43,7 @@ public:
|
|||||||
|
|
||||||
virtual void OnMsgChangeGame(const SyncIdentifier& sync_identifier,
|
virtual void OnMsgChangeGame(const SyncIdentifier& sync_identifier,
|
||||||
const std::string& netplay_name) = 0;
|
const std::string& netplay_name) = 0;
|
||||||
|
virtual void OnMsgChangeGBARom(int pad, const NetPlay::GBAConfig& config) = 0;
|
||||||
virtual void OnMsgStartGame() = 0;
|
virtual void OnMsgStartGame() = 0;
|
||||||
virtual void OnMsgStopGame() = 0;
|
virtual void OnMsgStopGame() = 0;
|
||||||
virtual void OnMsgPowerButton() = 0;
|
virtual void OnMsgPowerButton() = 0;
|
||||||
@ -62,6 +63,8 @@ public:
|
|||||||
virtual std::shared_ptr<const UICommon::GameFile>
|
virtual std::shared_ptr<const UICommon::GameFile>
|
||||||
FindGameFile(const SyncIdentifier& sync_identifier,
|
FindGameFile(const SyncIdentifier& sync_identifier,
|
||||||
SyncIdentifierComparison* found = nullptr) = 0;
|
SyncIdentifierComparison* found = nullptr) = 0;
|
||||||
|
virtual std::string FindGBARomPath(const std::array<u8, 20>& hash, std::string_view title,
|
||||||
|
int device_number) = 0;
|
||||||
virtual void ShowMD5Dialog(const std::string& title) = 0;
|
virtual void ShowMD5Dialog(const std::string& title) = 0;
|
||||||
virtual void SetMD5Progress(int pid, int progress) = 0;
|
virtual void SetMD5Progress(int pid, int progress) = 0;
|
||||||
virtual void SetMD5Result(int pid, const std::string& result) = 0;
|
virtual void SetMD5Result(int pid, const std::string& result) = 0;
|
||||||
@ -139,6 +142,7 @@ public:
|
|||||||
bool DoAllPlayersHaveGame();
|
bool DoAllPlayersHaveGame();
|
||||||
|
|
||||||
const PadMappingArray& GetPadMapping() const;
|
const PadMappingArray& GetPadMapping() const;
|
||||||
|
const GBAConfigArray& GetGBAConfig() const;
|
||||||
const PadMappingArray& GetWiimoteMapping() const;
|
const PadMappingArray& GetWiimoteMapping() const;
|
||||||
|
|
||||||
void AdjustPadBufferSize(unsigned int size);
|
void AdjustPadBufferSize(unsigned int size);
|
||||||
@ -199,8 +203,9 @@ protected:
|
|||||||
|
|
||||||
u32 m_current_game = 0;
|
u32 m_current_game = 0;
|
||||||
|
|
||||||
PadMappingArray m_pad_map;
|
PadMappingArray m_pad_map{};
|
||||||
PadMappingArray m_wiimote_map;
|
GBAConfigArray m_gba_config{};
|
||||||
|
PadMappingArray m_wiimote_map{};
|
||||||
|
|
||||||
bool m_is_recording = false;
|
bool m_is_recording = false;
|
||||||
|
|
||||||
@ -231,6 +236,7 @@ private:
|
|||||||
void Send(const sf::Packet& packet, u8 channel_id = DEFAULT_CHANNEL);
|
void Send(const sf::Packet& packet, u8 channel_id = DEFAULT_CHANNEL);
|
||||||
void Disconnect();
|
void Disconnect();
|
||||||
bool Connect();
|
bool Connect();
|
||||||
|
void SendGameStatus();
|
||||||
void ComputeMD5(const SyncIdentifier& sync_identifier);
|
void ComputeMD5(const SyncIdentifier& sync_identifier);
|
||||||
void DisplayPlayersPing();
|
void DisplayPlayersPing();
|
||||||
u32 GetPlayersMaxPing() const;
|
u32 GetPlayersMaxPing() const;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
@ -97,10 +98,12 @@ struct NetSettings
|
|||||||
std::array<int, 4> m_WiimoteExtension;
|
std::array<int, 4> m_WiimoteExtension;
|
||||||
bool m_GolfMode;
|
bool m_GolfMode;
|
||||||
bool m_UseFMA;
|
bool m_UseFMA;
|
||||||
|
bool m_HideRemoteGBAs;
|
||||||
|
|
||||||
// These aren't sent over the network directly
|
// These aren't sent over the network directly
|
||||||
bool m_IsHosting;
|
bool m_IsHosting;
|
||||||
bool m_HostInputAuthority;
|
bool m_HostInputAuthority;
|
||||||
|
std::array<std::string, 4> m_GBARomPaths;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NetTraversalConfig
|
struct NetTraversalConfig
|
||||||
@ -136,6 +139,7 @@ enum
|
|||||||
NP_MSG_PAD_MAPPING = 0x61,
|
NP_MSG_PAD_MAPPING = 0x61,
|
||||||
NP_MSG_PAD_BUFFER = 0x62,
|
NP_MSG_PAD_BUFFER = 0x62,
|
||||||
NP_MSG_PAD_HOST_DATA = 0x63,
|
NP_MSG_PAD_HOST_DATA = 0x63,
|
||||||
|
NP_MSG_GBA_CONFIG = 0x64,
|
||||||
|
|
||||||
NP_MSG_WIIMOTE_DATA = 0x70,
|
NP_MSG_WIIMOTE_DATA = 0x70,
|
||||||
NP_MSG_WIIMOTE_MAPPING = 0x71,
|
NP_MSG_WIIMOTE_MAPPING = 0x71,
|
||||||
@ -191,7 +195,8 @@ enum
|
|||||||
SYNC_SAVE_DATA_FAILURE = 2,
|
SYNC_SAVE_DATA_FAILURE = 2,
|
||||||
SYNC_SAVE_DATA_RAW = 3,
|
SYNC_SAVE_DATA_RAW = 3,
|
||||||
SYNC_SAVE_DATA_GCI = 4,
|
SYNC_SAVE_DATA_GCI = 4,
|
||||||
SYNC_SAVE_DATA_WII = 5
|
SYNC_SAVE_DATA_WII = 5,
|
||||||
|
SYNC_SAVE_DATA_GBA = 6
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@ -225,7 +230,26 @@ using PlayerId = u8;
|
|||||||
using FrameNum = u32;
|
using FrameNum = u32;
|
||||||
using PadIndex = s8;
|
using PadIndex = s8;
|
||||||
using PadMappingArray = std::array<PlayerId, 4>;
|
using PadMappingArray = std::array<PlayerId, 4>;
|
||||||
|
struct GBAConfig
|
||||||
|
{
|
||||||
|
bool enabled;
|
||||||
|
bool has_rom;
|
||||||
|
std::string title;
|
||||||
|
std::array<u8, 20> hash;
|
||||||
|
};
|
||||||
|
using GBAConfigArray = std::array<GBAConfig, 4>;
|
||||||
|
|
||||||
|
struct PadDetails
|
||||||
|
{
|
||||||
|
std::string player_name;
|
||||||
|
bool is_local;
|
||||||
|
int local_pad;
|
||||||
|
bool hide_gba;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string GetPlayerMappingString(PlayerId pid, const PadMappingArray& pad_map,
|
||||||
|
const GBAConfigArray& gba_config,
|
||||||
|
const PadMappingArray& wiimote_map);
|
||||||
bool IsNetPlayRunning();
|
bool IsNetPlayRunning();
|
||||||
// Precondition: A netplay client instance must be present. In other words,
|
// Precondition: A netplay client instance must be present. In other words,
|
||||||
// IsNetPlayRunning() must be true before calling this.
|
// IsNetPlayRunning() must be true before calling this.
|
||||||
@ -238,4 +262,6 @@ void SetSIPollBatching(bool state);
|
|||||||
void SendPowerButtonEvent();
|
void SendPowerButtonEvent();
|
||||||
bool IsSyncingAllWiiSaves();
|
bool IsSyncingAllWiiSaves();
|
||||||
void SetupWiimotes();
|
void SetupWiimotes();
|
||||||
|
std::string GetGBASavePath(int pad_num);
|
||||||
|
PadDetails GetPadDetails(int pad_num);
|
||||||
} // namespace NetPlay
|
} // namespace NetPlay
|
||||||
|
@ -40,6 +40,9 @@
|
|||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/GeckoCode.h"
|
#include "Core/GeckoCode.h"
|
||||||
#include "Core/GeckoCodeConfig.h"
|
#include "Core/GeckoCodeConfig.h"
|
||||||
|
#ifdef HAS_LIBMGBA
|
||||||
|
#include "Core/HW/GBACore.h"
|
||||||
|
#endif
|
||||||
#include "Core/HW/GCMemcard/GCMemcard.h"
|
#include "Core/HW/GCMemcard/GCMemcard.h"
|
||||||
#include "Core/HW/GCMemcard/GCMemcardDirectory.h"
|
#include "Core/HW/GCMemcard/GCMemcardDirectory.h"
|
||||||
#include "Core/HW/GCMemcard/GCMemcardRaw.h"
|
#include "Core/HW/GCMemcard/GCMemcardRaw.h"
|
||||||
@ -119,6 +122,7 @@ NetPlayServer::NetPlayServer(const u16 port, const bool forward_port, NetPlayUI*
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_pad_map.fill(0);
|
m_pad_map.fill(0);
|
||||||
|
m_gba_config.fill({});
|
||||||
m_wiimote_map.fill(0);
|
m_wiimote_map.fill(0);
|
||||||
|
|
||||||
if (traversal_config.use_traversal)
|
if (traversal_config.use_traversal)
|
||||||
@ -480,6 +484,7 @@ unsigned int NetPlayServer::OnConnect(ENetPeer* socket, sf::Packet& rpac)
|
|||||||
std::lock_guard lkp(m_crit.players);
|
std::lock_guard lkp(m_crit.players);
|
||||||
m_players.emplace(*PeerPlayerId(player.socket), std::move(player));
|
m_players.emplace(*PeerPlayerId(player.socket), std::move(player));
|
||||||
UpdatePadMapping(); // sync pad mappings with everyone
|
UpdatePadMapping(); // sync pad mappings with everyone
|
||||||
|
UpdateGBAConfig();
|
||||||
UpdateWiimoteMapping();
|
UpdateWiimoteMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,12 +535,14 @@ unsigned int NetPlayServer::OnDisconnect(const Client& player)
|
|||||||
// alert other players of disconnect
|
// alert other players of disconnect
|
||||||
SendToClients(spac);
|
SendToClients(spac);
|
||||||
|
|
||||||
for (PlayerId& mapping : m_pad_map)
|
for (size_t i = 0; i < m_pad_map.size(); ++i)
|
||||||
{
|
{
|
||||||
if (mapping == pid)
|
if (m_pad_map[i] == pid)
|
||||||
{
|
{
|
||||||
mapping = 0;
|
m_pad_map[i] = 0;
|
||||||
|
m_gba_config[i].enabled = false;
|
||||||
UpdatePadMapping();
|
UpdatePadMapping();
|
||||||
|
UpdateGBAConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,6 +564,11 @@ PadMappingArray NetPlayServer::GetPadMapping() const
|
|||||||
return m_pad_map;
|
return m_pad_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GBAConfigArray NetPlayServer::GetGBAConfig() const
|
||||||
|
{
|
||||||
|
return m_gba_config;
|
||||||
|
}
|
||||||
|
|
||||||
PadMappingArray NetPlayServer::GetWiimoteMapping() const
|
PadMappingArray NetPlayServer::GetWiimoteMapping() const
|
||||||
{
|
{
|
||||||
return m_wiimote_map;
|
return m_wiimote_map;
|
||||||
@ -569,6 +581,26 @@ void NetPlayServer::SetPadMapping(const PadMappingArray& mappings)
|
|||||||
UpdatePadMapping();
|
UpdatePadMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// called from ---GUI--- thread
|
||||||
|
void NetPlayServer::SetGBAConfig(const GBAConfigArray& mappings, bool update_rom)
|
||||||
|
{
|
||||||
|
#ifdef HAS_LIBMGBA
|
||||||
|
m_gba_config = mappings;
|
||||||
|
if (update_rom)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < m_gba_config.size(); ++i)
|
||||||
|
{
|
||||||
|
auto& config = m_gba_config[i];
|
||||||
|
if (!config.enabled)
|
||||||
|
continue;
|
||||||
|
std::string rom_path = Config::Get(Config::MAIN_GBA_ROM_PATHS[i]);
|
||||||
|
config.has_rom = HW::GBA::Core::GetRomInfo(rom_path.c_str(), config.hash, config.title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
UpdateGBAConfig();
|
||||||
|
}
|
||||||
|
|
||||||
// called from ---GUI--- thread
|
// called from ---GUI--- thread
|
||||||
void NetPlayServer::SetWiimoteMapping(const PadMappingArray& mappings)
|
void NetPlayServer::SetWiimoteMapping(const PadMappingArray& mappings)
|
||||||
{
|
{
|
||||||
@ -588,6 +620,20 @@ void NetPlayServer::UpdatePadMapping()
|
|||||||
SendToClients(spac);
|
SendToClients(spac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// called from ---GUI--- thread and ---NETPLAY--- thread
|
||||||
|
void NetPlayServer::UpdateGBAConfig()
|
||||||
|
{
|
||||||
|
sf::Packet spac;
|
||||||
|
spac << static_cast<MessageId>(NP_MSG_GBA_CONFIG);
|
||||||
|
for (const auto& config : m_gba_config)
|
||||||
|
{
|
||||||
|
spac << config.enabled << config.has_rom << config.title;
|
||||||
|
for (auto& data : config.hash)
|
||||||
|
spac << data;
|
||||||
|
}
|
||||||
|
SendToClients(spac);
|
||||||
|
}
|
||||||
|
|
||||||
// called from ---NETPLAY--- thread
|
// called from ---NETPLAY--- thread
|
||||||
void NetPlayServer::UpdateWiimoteMapping()
|
void NetPlayServer::UpdateWiimoteMapping()
|
||||||
{
|
{
|
||||||
@ -751,12 +797,16 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
|
|||||||
}
|
}
|
||||||
|
|
||||||
GCPadStatus pad;
|
GCPadStatus pad;
|
||||||
packet >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >>
|
packet >> pad.button;
|
||||||
pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
spac << map << pad.button;
|
||||||
|
if (!m_gba_config.at(map).enabled)
|
||||||
|
{
|
||||||
|
packet >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >> pad.substickX >>
|
||||||
|
pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
||||||
|
|
||||||
spac << map << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY
|
spac << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX
|
||||||
<< pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight
|
<< pad.substickY << pad.triggerLeft << pad.triggerRight << pad.isConnected;
|
||||||
<< pad.isConnected;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_host_input_authority)
|
if (m_host_input_authority)
|
||||||
@ -787,12 +837,16 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
|
|||||||
packet >> map;
|
packet >> map;
|
||||||
|
|
||||||
GCPadStatus pad;
|
GCPadStatus pad;
|
||||||
packet >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >>
|
packet >> pad.button;
|
||||||
pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
spac << map << pad.button;
|
||||||
|
if (!m_gba_config.at(map).enabled)
|
||||||
|
{
|
||||||
|
packet >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >> pad.substickX >>
|
||||||
|
pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
||||||
|
|
||||||
spac << map << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY
|
spac << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX
|
||||||
<< pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight
|
<< pad.substickY << pad.triggerLeft << pad.triggerRight << pad.isConnected;
|
||||||
<< pad.isConnected;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SendToClients(spac, player.pid);
|
SendToClients(spac, player.pid);
|
||||||
@ -1316,6 +1370,7 @@ bool NetPlayServer::SetupNetSettings()
|
|||||||
Config::Get(Config::NETPLAY_SYNC_ALL_WII_SAVES) && Config::Get(Config::NETPLAY_SYNC_SAVES);
|
Config::Get(Config::NETPLAY_SYNC_ALL_WII_SAVES) && Config::Get(Config::NETPLAY_SYNC_SAVES);
|
||||||
settings.m_GolfMode = Config::Get(Config::NETPLAY_NETWORK_MODE) == "golf";
|
settings.m_GolfMode = Config::Get(Config::NETPLAY_NETWORK_MODE) == "golf";
|
||||||
settings.m_UseFMA = DoAllPlayersHaveHardwareFMA();
|
settings.m_UseFMA = DoAllPlayersHaveHardwareFMA();
|
||||||
|
settings.m_HideRemoteGBAs = Config::Get(Config::NETPLAY_HIDE_REMOTE_GBAS);
|
||||||
|
|
||||||
// Unload GameINI to restore things to normal
|
// Unload GameINI to restore things to normal
|
||||||
Config::RemoveLayer(Config::LayerType::GlobalGame);
|
Config::RemoveLayer(Config::LayerType::GlobalGame);
|
||||||
@ -1501,6 +1556,7 @@ bool NetPlayServer::StartGame()
|
|||||||
|
|
||||||
spac << m_settings.m_GolfMode;
|
spac << m_settings.m_GolfMode;
|
||||||
spac << m_settings.m_UseFMA;
|
spac << m_settings.m_UseFMA;
|
||||||
|
spac << m_settings.m_HideRemoteGBAs;
|
||||||
|
|
||||||
SendAsyncToClients(std::move(spac));
|
SendAsyncToClients(std::move(spac));
|
||||||
|
|
||||||
@ -1556,6 +1612,12 @@ bool NetPlayServer::SyncSaveData()
|
|||||||
save_count++;
|
save_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& config : m_gba_config)
|
||||||
|
{
|
||||||
|
if (config.enabled && config.has_rom)
|
||||||
|
save_count++;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
sf::Packet pac;
|
sf::Packet pac;
|
||||||
pac << static_cast<MessageId>(NP_MSG_SYNC_SAVE_DATA);
|
pac << static_cast<MessageId>(NP_MSG_SYNC_SAVE_DATA);
|
||||||
@ -1758,6 +1820,36 @@ bool NetPlayServer::SyncSaveData()
|
|||||||
SendChunkedToClients(std::move(pac), 1, "Wii Save Synchronization");
|
SendChunkedToClients(std::move(pac), 1, "Wii Save Synchronization");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_gba_config.size(); ++i)
|
||||||
|
{
|
||||||
|
if (m_gba_config[i].enabled && m_gba_config[i].has_rom)
|
||||||
|
{
|
||||||
|
sf::Packet pac;
|
||||||
|
pac << static_cast<MessageId>(NP_MSG_SYNC_SAVE_DATA);
|
||||||
|
pac << static_cast<MessageId>(SYNC_SAVE_DATA_GBA);
|
||||||
|
pac << static_cast<u8>(i);
|
||||||
|
|
||||||
|
std::string path;
|
||||||
|
#ifdef HAS_LIBMGBA
|
||||||
|
path = HW::GBA::Core::GetSavePath(Config::Get(Config::MAIN_GBA_ROM_PATHS[i]),
|
||||||
|
static_cast<int>(i));
|
||||||
|
#endif
|
||||||
|
if (File::Exists(path))
|
||||||
|
{
|
||||||
|
if (!CompressFileIntoPacket(path, pac))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No file, so we'll say the size is 0
|
||||||
|
pac << sf::Uint64{0};
|
||||||
|
}
|
||||||
|
|
||||||
|
SendChunkedToClients(std::move(pac), 1,
|
||||||
|
fmt::format("GBA{} Save File Synchronization", i + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,9 @@ public:
|
|||||||
PadMappingArray GetPadMapping() const;
|
PadMappingArray GetPadMapping() const;
|
||||||
void SetPadMapping(const PadMappingArray& mappings);
|
void SetPadMapping(const PadMappingArray& mappings);
|
||||||
|
|
||||||
|
GBAConfigArray GetGBAConfig() const;
|
||||||
|
void SetGBAConfig(const GBAConfigArray& configs, bool update_rom);
|
||||||
|
|
||||||
PadMappingArray GetWiimoteMapping() const;
|
PadMappingArray GetWiimoteMapping() const;
|
||||||
void SetWiimoteMapping(const PadMappingArray& mappings);
|
void SetWiimoteMapping(const PadMappingArray& mappings);
|
||||||
|
|
||||||
@ -134,6 +137,7 @@ private:
|
|||||||
void OnConnectReady(ENetAddress) override {}
|
void OnConnectReady(ENetAddress) override {}
|
||||||
void OnConnectFailed(TraversalConnectFailedReason) override {}
|
void OnConnectFailed(TraversalConnectFailedReason) override {}
|
||||||
void UpdatePadMapping();
|
void UpdatePadMapping();
|
||||||
|
void UpdateGBAConfig();
|
||||||
void UpdateWiimoteMapping();
|
void UpdateWiimoteMapping();
|
||||||
std::vector<std::pair<std::string, std::string>> GetInterfaceListInternal() const;
|
std::vector<std::pair<std::string, std::string>> GetInterfaceListInternal() const;
|
||||||
void ChunkedDataThreadFunc();
|
void ChunkedDataThreadFunc();
|
||||||
@ -153,6 +157,7 @@ private:
|
|||||||
u32 m_current_game = 0;
|
u32 m_current_game = 0;
|
||||||
unsigned int m_target_buffer_size = 0;
|
unsigned int m_target_buffer_size = 0;
|
||||||
PadMappingArray m_pad_map;
|
PadMappingArray m_pad_map;
|
||||||
|
GBAConfigArray m_gba_config;
|
||||||
PadMappingArray m_wiimote_map;
|
PadMappingArray m_wiimote_map;
|
||||||
unsigned int m_save_data_synced_players = 0;
|
unsigned int m_save_data_synced_players = 0;
|
||||||
unsigned int m_codes_synced_players = 0;
|
unsigned int m_codes_synced_players = 0;
|
||||||
|
@ -58,6 +58,17 @@ GBAWidget::GBAWidget(std::weak_ptr<HW::GBA::Core> core, int device_number,
|
|||||||
m_is_local_pad(true), m_volume(0), m_muted(false), m_force_disconnect(false)
|
m_is_local_pad(true), m_volume(0), m_muted(false), m_force_disconnect(false)
|
||||||
{
|
{
|
||||||
bool visible = true;
|
bool visible = true;
|
||||||
|
if (NetPlay::IsNetPlayRunning())
|
||||||
|
{
|
||||||
|
NetPlay::PadDetails details = NetPlay::GetPadDetails(m_device_number);
|
||||||
|
if (details.local_pad < 4)
|
||||||
|
{
|
||||||
|
m_netplayer_name = details.player_name;
|
||||||
|
m_is_local_pad = details.is_local;
|
||||||
|
m_local_pad = details.local_pad;
|
||||||
|
visible = !details.hide_gba;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setWindowIcon(Resources::GetAppIcon());
|
setWindowIcon(Resources::GetAppIcon());
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
#include <QFileDialog>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
#include <QGroupBox>
|
#include <QGroupBox>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
@ -35,6 +36,9 @@
|
|||||||
#include "Core/Config/NetplaySettings.h"
|
#include "Core/Config/NetplaySettings.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
|
#ifdef HAS_LIBMGBA
|
||||||
|
#include "Core/HW/GBACore.h"
|
||||||
|
#endif
|
||||||
#include "Core/NetPlayServer.h"
|
#include "Core/NetPlayServer.h"
|
||||||
#include "Core/SyncIdentifier.h"
|
#include "Core/SyncIdentifier.h"
|
||||||
|
|
||||||
@ -47,6 +51,7 @@
|
|||||||
#include "DolphinQt/QtUtils/RunOnObject.h"
|
#include "DolphinQt/QtUtils/RunOnObject.h"
|
||||||
#include "DolphinQt/Resources.h"
|
#include "DolphinQt/Resources.h"
|
||||||
#include "DolphinQt/Settings.h"
|
#include "DolphinQt/Settings.h"
|
||||||
|
#include "DolphinQt/Settings/GameCubePane.h"
|
||||||
|
|
||||||
#include "UICommon/DiscordPresence.h"
|
#include "UICommon/DiscordPresence.h"
|
||||||
#include "UICommon/GameFile.h"
|
#include "UICommon/GameFile.h"
|
||||||
@ -171,6 +176,8 @@ void NetPlayDialog::CreateMainLayout()
|
|||||||
m_record_input_action->setCheckable(true);
|
m_record_input_action->setCheckable(true);
|
||||||
m_golf_mode_overlay_action = m_other_menu->addAction(tr("Show Golf Mode Overlay"));
|
m_golf_mode_overlay_action = m_other_menu->addAction(tr("Show Golf Mode Overlay"));
|
||||||
m_golf_mode_overlay_action->setCheckable(true);
|
m_golf_mode_overlay_action->setCheckable(true);
|
||||||
|
m_hide_remote_gbas_action = m_other_menu->addAction(tr("Hide Remote GBAs"));
|
||||||
|
m_hide_remote_gbas_action->setCheckable(true);
|
||||||
|
|
||||||
m_game_button->setDefault(false);
|
m_game_button->setDefault(false);
|
||||||
m_game_button->setAutoDefault(false);
|
m_game_button->setAutoDefault(false);
|
||||||
@ -279,6 +286,7 @@ void NetPlayDialog::ConnectWidgets()
|
|||||||
m_pad_mapping->exec();
|
m_pad_mapping->exec();
|
||||||
|
|
||||||
Settings::Instance().GetNetPlayServer()->SetPadMapping(m_pad_mapping->GetGCPadArray());
|
Settings::Instance().GetNetPlayServer()->SetPadMapping(m_pad_mapping->GetGCPadArray());
|
||||||
|
Settings::Instance().GetNetPlayServer()->SetGBAConfig(m_pad_mapping->GetGBAArray(), true);
|
||||||
Settings::Instance().GetNetPlayServer()->SetWiimoteMapping(m_pad_mapping->GetWiimoteArray());
|
Settings::Instance().GetNetPlayServer()->SetWiimoteMapping(m_pad_mapping->GetWiimoteArray());
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -365,6 +373,7 @@ void NetPlayDialog::ConnectWidgets()
|
|||||||
connect(m_golf_mode_action, &QAction::toggled, this, &NetPlayDialog::SaveSettings);
|
connect(m_golf_mode_action, &QAction::toggled, this, &NetPlayDialog::SaveSettings);
|
||||||
connect(m_golf_mode_overlay_action, &QAction::toggled, this, &NetPlayDialog::SaveSettings);
|
connect(m_golf_mode_overlay_action, &QAction::toggled, this, &NetPlayDialog::SaveSettings);
|
||||||
connect(m_fixed_delay_action, &QAction::toggled, this, &NetPlayDialog::SaveSettings);
|
connect(m_fixed_delay_action, &QAction::toggled, this, &NetPlayDialog::SaveSettings);
|
||||||
|
connect(m_hide_remote_gbas_action, &QAction::toggled, this, &NetPlayDialog::SaveSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetPlayDialog::SendMessage(const std::string& msg)
|
void NetPlayDialog::SendMessage(const std::string& msg)
|
||||||
@ -471,6 +480,11 @@ void NetPlayDialog::show(std::string nickname, bool use_traversal)
|
|||||||
m_data_menu->menuAction()->setVisible(is_hosting);
|
m_data_menu->menuAction()->setVisible(is_hosting);
|
||||||
m_network_menu->menuAction()->setVisible(is_hosting);
|
m_network_menu->menuAction()->setVisible(is_hosting);
|
||||||
m_md5_menu->menuAction()->setVisible(is_hosting);
|
m_md5_menu->menuAction()->setVisible(is_hosting);
|
||||||
|
#ifdef HAS_LIBMGBA
|
||||||
|
m_hide_remote_gbas_action->setVisible(is_hosting);
|
||||||
|
#else
|
||||||
|
m_hide_remote_gbas_action->setVisible(false);
|
||||||
|
#endif
|
||||||
m_start_button->setHidden(!is_hosting);
|
m_start_button->setHidden(!is_hosting);
|
||||||
m_kick_button->setHidden(!is_hosting);
|
m_kick_button->setHidden(!is_hosting);
|
||||||
m_assign_ports_button->setHidden(!is_hosting);
|
m_assign_ports_button->setHidden(!is_hosting);
|
||||||
@ -570,20 +584,6 @@ void NetPlayDialog::UpdateGUI()
|
|||||||
{tr("Player"), tr("Game Status"), tr("Ping"), tr("Mapping"), tr("Revision")});
|
{tr("Player"), tr("Game Status"), tr("Ping"), tr("Mapping"), tr("Revision")});
|
||||||
m_players_list->setRowCount(m_player_count);
|
m_players_list->setRowCount(m_player_count);
|
||||||
|
|
||||||
const auto get_mapping_string = [](const NetPlay::Player* player,
|
|
||||||
const NetPlay::PadMappingArray& array) {
|
|
||||||
std::string str;
|
|
||||||
for (size_t i = 0; i < array.size(); i++)
|
|
||||||
{
|
|
||||||
if (player->pid == array[i])
|
|
||||||
str += std::to_string(i + 1);
|
|
||||||
else
|
|
||||||
str += '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
return '|' + str + '|';
|
|
||||||
};
|
|
||||||
|
|
||||||
static const std::map<NetPlay::SyncIdentifierComparison, QString> player_status{
|
static const std::map<NetPlay::SyncIdentifierComparison, QString> player_status{
|
||||||
{NetPlay::SyncIdentifierComparison::SameGame, tr("OK")},
|
{NetPlay::SyncIdentifierComparison::SameGame, tr("OK")},
|
||||||
{NetPlay::SyncIdentifierComparison::DifferentVersion, tr("Wrong Version")},
|
{NetPlay::SyncIdentifierComparison::DifferentVersion, tr("Wrong Version")},
|
||||||
@ -599,9 +599,9 @@ void NetPlayDialog::UpdateGUI()
|
|||||||
player_status.at(p->game_status) :
|
player_status.at(p->game_status) :
|
||||||
QStringLiteral("?"));
|
QStringLiteral("?"));
|
||||||
auto* ping_item = new QTableWidgetItem(QStringLiteral("%1 ms").arg(p->ping));
|
auto* ping_item = new QTableWidgetItem(QStringLiteral("%1 ms").arg(p->ping));
|
||||||
auto* mapping_item = new QTableWidgetItem(
|
auto* mapping_item =
|
||||||
QString::fromStdString(get_mapping_string(p, client->GetPadMapping()) +
|
new QTableWidgetItem(QString::fromStdString(NetPlay::GetPlayerMappingString(
|
||||||
get_mapping_string(p, client->GetWiimoteMapping())));
|
p->pid, client->GetPadMapping(), client->GetGBAConfig(), client->GetWiimoteMapping())));
|
||||||
auto* revision_item = new QTableWidgetItem(QString::fromStdString(p->revision));
|
auto* revision_item = new QTableWidgetItem(QString::fromStdString(p->revision));
|
||||||
|
|
||||||
for (auto* item : {name_item, status_item, ping_item, mapping_item, revision_item})
|
for (auto* item : {name_item, status_item, ping_item, mapping_item, revision_item})
|
||||||
@ -743,6 +743,20 @@ void NetPlayDialog::OnMsgChangeGame(const NetPlay::SyncIdentifier& sync_identifi
|
|||||||
DisplayMessage(tr("Game changed to \"%1\"").arg(qname), "magenta");
|
DisplayMessage(tr("Game changed to \"%1\"").arg(qname), "magenta");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetPlayDialog::OnMsgChangeGBARom(int pad, const NetPlay::GBAConfig& config)
|
||||||
|
{
|
||||||
|
if (config.has_rom)
|
||||||
|
{
|
||||||
|
DisplayMessage(
|
||||||
|
tr("GBA%1 ROM changed to \"%2\"").arg(pad + 1).arg(QString::fromStdString(config.title)),
|
||||||
|
"magenta");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DisplayMessage(tr("GBA%1 ROM disabled").arg(pad + 1), "magenta");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NetPlayDialog::GameStatusChanged(bool running)
|
void NetPlayDialog::GameStatusChanged(bool running)
|
||||||
{
|
{
|
||||||
QueueOnObject(this, [this, running] { SetOptionsEnabled(!running); });
|
QueueOnObject(this, [this, running] { SetOptionsEnabled(!running); });
|
||||||
@ -976,6 +990,51 @@ NetPlayDialog::FindGameFile(const NetPlay::SyncIdentifier& sync_identifier,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string NetPlayDialog::FindGBARomPath(const std::array<u8, 20>& hash, std::string_view title,
|
||||||
|
int device_number)
|
||||||
|
{
|
||||||
|
#ifdef HAS_LIBMGBA
|
||||||
|
auto result = RunOnObject(this, [&, this] {
|
||||||
|
std::string rom_path;
|
||||||
|
std::array<u8, 20> rom_hash;
|
||||||
|
std::string rom_title;
|
||||||
|
for (size_t i = device_number; i < static_cast<size_t>(device_number) + 4; ++i)
|
||||||
|
{
|
||||||
|
rom_path = Config::Get(Config::MAIN_GBA_ROM_PATHS[i % 4]);
|
||||||
|
if (!rom_path.empty() && HW::GBA::Core::GetRomInfo(rom_path.c_str(), rom_hash, rom_title) &&
|
||||||
|
rom_hash == hash && rom_title == title)
|
||||||
|
{
|
||||||
|
return rom_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!(rom_path = GameCubePane::GetOpenGBARom(title)).empty())
|
||||||
|
{
|
||||||
|
if (HW::GBA::Core::GetRomInfo(rom_path.c_str(), rom_hash, rom_title))
|
||||||
|
{
|
||||||
|
if (rom_hash == hash && rom_title == title)
|
||||||
|
return rom_path;
|
||||||
|
ModalMessageBox::critical(
|
||||||
|
this, tr("Error"),
|
||||||
|
QString::fromStdString(Common::FmtFormatT(
|
||||||
|
"Mismatched ROMs\n"
|
||||||
|
"Selected: {0}\n- Title: {1}\n- Hash: {2:02X}\n"
|
||||||
|
"Expected:\n- Title: {3}\n- Hash: {4:02X}",
|
||||||
|
rom_path, rom_title, fmt::join(rom_hash, ""), title, fmt::join(hash, ""))));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ModalMessageBox::critical(
|
||||||
|
this, tr("Error"), tr("%1 is not a valid ROM").arg(QString::fromStdString(rom_path)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::string();
|
||||||
|
});
|
||||||
|
if (result)
|
||||||
|
return *result;
|
||||||
|
#endif
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void NetPlayDialog::LoadSettings()
|
void NetPlayDialog::LoadSettings()
|
||||||
{
|
{
|
||||||
const int buffer_size = Config::Get(Config::NETPLAY_BUFFER_SIZE);
|
const int buffer_size = Config::Get(Config::NETPLAY_BUFFER_SIZE);
|
||||||
@ -987,6 +1046,7 @@ void NetPlayDialog::LoadSettings()
|
|||||||
const bool strict_settings_sync = Config::Get(Config::NETPLAY_STRICT_SETTINGS_SYNC);
|
const bool strict_settings_sync = Config::Get(Config::NETPLAY_STRICT_SETTINGS_SYNC);
|
||||||
const bool sync_all_wii_saves = Config::Get(Config::NETPLAY_SYNC_ALL_WII_SAVES);
|
const bool sync_all_wii_saves = Config::Get(Config::NETPLAY_SYNC_ALL_WII_SAVES);
|
||||||
const bool golf_mode_overlay = Config::Get(Config::NETPLAY_GOLF_MODE_OVERLAY);
|
const bool golf_mode_overlay = Config::Get(Config::NETPLAY_GOLF_MODE_OVERLAY);
|
||||||
|
const bool hide_remote_gbas = Config::Get(Config::NETPLAY_HIDE_REMOTE_GBAS);
|
||||||
|
|
||||||
m_buffer_size_box->setValue(buffer_size);
|
m_buffer_size_box->setValue(buffer_size);
|
||||||
m_save_sd_action->setChecked(write_save_sdcard_data);
|
m_save_sd_action->setChecked(write_save_sdcard_data);
|
||||||
@ -997,6 +1057,7 @@ void NetPlayDialog::LoadSettings()
|
|||||||
m_strict_settings_sync_action->setChecked(strict_settings_sync);
|
m_strict_settings_sync_action->setChecked(strict_settings_sync);
|
||||||
m_sync_all_wii_saves_action->setChecked(sync_all_wii_saves);
|
m_sync_all_wii_saves_action->setChecked(sync_all_wii_saves);
|
||||||
m_golf_mode_overlay_action->setChecked(golf_mode_overlay);
|
m_golf_mode_overlay_action->setChecked(golf_mode_overlay);
|
||||||
|
m_hide_remote_gbas_action->setChecked(hide_remote_gbas);
|
||||||
|
|
||||||
const std::string network_mode = Config::Get(Config::NETPLAY_NETWORK_MODE);
|
const std::string network_mode = Config::Get(Config::NETPLAY_NETWORK_MODE);
|
||||||
|
|
||||||
@ -1036,6 +1097,7 @@ void NetPlayDialog::SaveSettings()
|
|||||||
Config::SetBase(Config::NETPLAY_STRICT_SETTINGS_SYNC, m_strict_settings_sync_action->isChecked());
|
Config::SetBase(Config::NETPLAY_STRICT_SETTINGS_SYNC, m_strict_settings_sync_action->isChecked());
|
||||||
Config::SetBase(Config::NETPLAY_SYNC_ALL_WII_SAVES, m_sync_all_wii_saves_action->isChecked());
|
Config::SetBase(Config::NETPLAY_SYNC_ALL_WII_SAVES, m_sync_all_wii_saves_action->isChecked());
|
||||||
Config::SetBase(Config::NETPLAY_GOLF_MODE_OVERLAY, m_golf_mode_overlay_action->isChecked());
|
Config::SetBase(Config::NETPLAY_GOLF_MODE_OVERLAY, m_golf_mode_overlay_action->isChecked());
|
||||||
|
Config::SetBase(Config::NETPLAY_HIDE_REMOTE_GBAS, m_hide_remote_gbas_action->isChecked());
|
||||||
|
|
||||||
std::string network_mode;
|
std::string network_mode;
|
||||||
if (m_fixed_delay_action->isChecked())
|
if (m_fixed_delay_action->isChecked())
|
||||||
|
@ -46,6 +46,7 @@ public:
|
|||||||
|
|
||||||
void OnMsgChangeGame(const NetPlay::SyncIdentifier& sync_identifier,
|
void OnMsgChangeGame(const NetPlay::SyncIdentifier& sync_identifier,
|
||||||
const std::string& netplay_name) override;
|
const std::string& netplay_name) override;
|
||||||
|
void OnMsgChangeGBARom(int pad, const NetPlay::GBAConfig& config) override;
|
||||||
void OnMsgStartGame() override;
|
void OnMsgStartGame() override;
|
||||||
void OnMsgStopGame() override;
|
void OnMsgStopGame() override;
|
||||||
void OnMsgPowerButton() override;
|
void OnMsgPowerButton() override;
|
||||||
@ -68,6 +69,8 @@ public:
|
|||||||
std::shared_ptr<const UICommon::GameFile>
|
std::shared_ptr<const UICommon::GameFile>
|
||||||
FindGameFile(const NetPlay::SyncIdentifier& sync_identifier,
|
FindGameFile(const NetPlay::SyncIdentifier& sync_identifier,
|
||||||
NetPlay::SyncIdentifierComparison* found = nullptr) override;
|
NetPlay::SyncIdentifierComparison* found = nullptr) override;
|
||||||
|
std::string FindGBARomPath(const std::array<u8, 20>& hash, std::string_view title,
|
||||||
|
int device_number) override;
|
||||||
|
|
||||||
void LoadSettings();
|
void LoadSettings();
|
||||||
void SaveSettings();
|
void SaveSettings();
|
||||||
@ -138,6 +141,7 @@ private:
|
|||||||
QAction* m_golf_mode_action;
|
QAction* m_golf_mode_action;
|
||||||
QAction* m_golf_mode_overlay_action;
|
QAction* m_golf_mode_overlay_action;
|
||||||
QAction* m_fixed_delay_action;
|
QAction* m_fixed_delay_action;
|
||||||
|
QAction* m_hide_remote_gbas_action;
|
||||||
QPushButton* m_quit_button;
|
QPushButton* m_quit_button;
|
||||||
QSplitter* m_splitter;
|
QSplitter* m_splitter;
|
||||||
QActionGroup* m_network_mode_group;
|
QActionGroup* m_network_mode_group;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "DolphinQt/NetPlay/PadMappingDialog.h"
|
#include "DolphinQt/NetPlay/PadMappingDialog.h"
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
@ -31,15 +32,19 @@ void PadMappingDialog::CreateWidgets()
|
|||||||
for (unsigned int i = 0; i < m_wii_boxes.size(); i++)
|
for (unsigned int i = 0; i < m_wii_boxes.size(); i++)
|
||||||
{
|
{
|
||||||
m_gc_boxes[i] = new QComboBox;
|
m_gc_boxes[i] = new QComboBox;
|
||||||
|
m_gba_boxes[i] = new QCheckBox(tr("GBA Port %1").arg(i + 1));
|
||||||
m_wii_boxes[i] = new QComboBox;
|
m_wii_boxes[i] = new QComboBox;
|
||||||
|
|
||||||
m_main_layout->addWidget(new QLabel(tr("GC Port %1").arg(i + 1)), 0, i);
|
m_main_layout->addWidget(new QLabel(tr("GC Port %1").arg(i + 1)), 0, i);
|
||||||
m_main_layout->addWidget(m_gc_boxes[i], 1, i);
|
m_main_layout->addWidget(m_gc_boxes[i], 1, i);
|
||||||
m_main_layout->addWidget(new QLabel(tr("Wii Remote %1").arg(i + 1)), 2, i);
|
#ifdef HAS_LIBMGBA
|
||||||
m_main_layout->addWidget(m_wii_boxes[i], 3, i);
|
m_main_layout->addWidget(m_gba_boxes[i], 2, i);
|
||||||
|
#endif
|
||||||
|
m_main_layout->addWidget(new QLabel(tr("Wii Remote %1").arg(i + 1)), 3, i);
|
||||||
|
m_main_layout->addWidget(m_wii_boxes[i], 4, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_main_layout->addWidget(m_button_box, 4, 0, 1, -1);
|
m_main_layout->addWidget(m_button_box, 5, 0, 1, -1);
|
||||||
|
|
||||||
setLayout(m_main_layout);
|
setLayout(m_main_layout);
|
||||||
}
|
}
|
||||||
@ -55,6 +60,11 @@ void PadMappingDialog::ConnectWidgets()
|
|||||||
&PadMappingDialog::OnMappingChanged);
|
&PadMappingDialog::OnMappingChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (const auto& checkbox : m_gba_boxes)
|
||||||
|
{
|
||||||
|
connect(checkbox, qOverload<int>(&QCheckBox::stateChanged), this,
|
||||||
|
&PadMappingDialog::OnMappingChanged);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int PadMappingDialog::exec()
|
int PadMappingDialog::exec()
|
||||||
@ -64,6 +74,7 @@ int PadMappingDialog::exec()
|
|||||||
// Load Settings
|
// Load Settings
|
||||||
m_players = client->GetPlayers();
|
m_players = client->GetPlayers();
|
||||||
m_pad_mapping = server->GetPadMapping();
|
m_pad_mapping = server->GetPadMapping();
|
||||||
|
m_gba_config = server->GetGBAConfig();
|
||||||
m_wii_mapping = server->GetWiimoteMapping();
|
m_wii_mapping = server->GetWiimoteMapping();
|
||||||
|
|
||||||
QStringList players;
|
QStringList players;
|
||||||
@ -93,6 +104,13 @@ int PadMappingDialog::exec()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_gba_boxes.size(); i++)
|
||||||
|
{
|
||||||
|
const QSignalBlocker blocker(m_gba_boxes[i]);
|
||||||
|
|
||||||
|
m_gba_boxes[i]->setChecked(m_gba_config[i].enabled);
|
||||||
|
}
|
||||||
|
|
||||||
return QDialog::exec();
|
return QDialog::exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +119,11 @@ NetPlay::PadMappingArray PadMappingDialog::GetGCPadArray()
|
|||||||
return m_pad_mapping;
|
return m_pad_mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetPlay::GBAConfigArray PadMappingDialog::GetGBAArray()
|
||||||
|
{
|
||||||
|
return m_gba_config;
|
||||||
|
}
|
||||||
|
|
||||||
NetPlay::PadMappingArray PadMappingDialog::GetWiimoteArray()
|
NetPlay::PadMappingArray PadMappingDialog::GetWiimoteArray()
|
||||||
{
|
{
|
||||||
return m_wii_mapping;
|
return m_wii_mapping;
|
||||||
@ -114,6 +137,7 @@ void PadMappingDialog::OnMappingChanged()
|
|||||||
int wii_id = m_wii_boxes[i]->currentIndex();
|
int wii_id = m_wii_boxes[i]->currentIndex();
|
||||||
|
|
||||||
m_pad_mapping[i] = gc_id > 0 ? m_players[gc_id - 1]->pid : 0;
|
m_pad_mapping[i] = gc_id > 0 ? m_players[gc_id - 1]->pid : 0;
|
||||||
|
m_gba_config[i].enabled = m_gba_boxes[i]->isChecked();
|
||||||
m_wii_mapping[i] = wii_id > 0 ? m_players[wii_id - 1]->pid : 0;
|
m_wii_mapping[i] = wii_id > 0 ? m_players[wii_id - 1]->pid : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "Core/NetPlayProto.h"
|
#include "Core/NetPlayProto.h"
|
||||||
|
|
||||||
|
class QCheckBox;
|
||||||
class QGridLayout;
|
class QGridLayout;
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
class QDialogButtonBox;
|
class QDialogButtonBox;
|
||||||
@ -25,6 +26,7 @@ public:
|
|||||||
int exec() override;
|
int exec() override;
|
||||||
|
|
||||||
NetPlay::PadMappingArray GetGCPadArray();
|
NetPlay::PadMappingArray GetGCPadArray();
|
||||||
|
NetPlay::GBAConfigArray GetGBAArray();
|
||||||
NetPlay::PadMappingArray GetWiimoteArray();
|
NetPlay::PadMappingArray GetWiimoteArray();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -34,10 +36,12 @@ private:
|
|||||||
void OnMappingChanged();
|
void OnMappingChanged();
|
||||||
|
|
||||||
NetPlay::PadMappingArray m_pad_mapping;
|
NetPlay::PadMappingArray m_pad_mapping;
|
||||||
|
NetPlay::GBAConfigArray m_gba_config;
|
||||||
NetPlay::PadMappingArray m_wii_mapping;
|
NetPlay::PadMappingArray m_wii_mapping;
|
||||||
|
|
||||||
QGridLayout* m_main_layout;
|
QGridLayout* m_main_layout;
|
||||||
std::array<QComboBox*, 4> m_gc_boxes;
|
std::array<QComboBox*, 4> m_gc_boxes;
|
||||||
|
std::array<QCheckBox*, 4> m_gba_boxes;
|
||||||
std::array<QComboBox*, 4> m_wii_boxes;
|
std::array<QComboBox*, 4> m_wii_boxes;
|
||||||
std::vector<const NetPlay::Player*> m_players;
|
std::vector<const NetPlay::Player*> m_players;
|
||||||
QDialogButtonBox* m_button_box;
|
QDialogButtonBox* m_button_box;
|
||||||
|
@ -542,6 +542,10 @@ void GameCubePane::SaveSettings()
|
|||||||
Config::SetBaseOrCurrent(Config::MAIN_GBA_ROM_PATHS[i],
|
Config::SetBaseOrCurrent(Config::MAIN_GBA_ROM_PATHS[i],
|
||||||
m_gba_rom_edits[i]->text().toStdString());
|
m_gba_rom_edits[i]->text().toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto server = Settings::Instance().GetNetPlayServer();
|
||||||
|
if (server)
|
||||||
|
server->SetGBAConfig(server->GetGBAConfig(), true);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user