NetPlay: GBA Support
This commit is contained in:
parent
b73d16a71a
commit
45f2461a53
|
@ -122,6 +122,7 @@
|
|||
#define GC_MEMCARD_NETPLAY "NetPlayTemp"
|
||||
|
||||
#define GBA_BIOS "gba_bios.bin"
|
||||
#define GBA_SAVE_NETPLAY "NetPlayTemp"
|
||||
|
||||
#define WII_STATE "state.dat"
|
||||
|
||||
|
|
|
@ -57,5 +57,6 @@ const Info<std::string> NETPLAY_NETWORK_MODE{{System::Main, "NetPlay", "NetworkM
|
|||
"fixeddelay"};
|
||||
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_HIDE_REMOTE_GBAS{{System::Main, "NetPlay", "HideRemoteGBAs"}, false};
|
||||
|
||||
} // 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<bool> NETPLAY_SYNC_ALL_WII_SAVES;
|
||||
extern const Info<bool> NETPLAY_GOLF_MODE_OVERLAY;
|
||||
extern const Info<bool> NETPLAY_HIDE_REMOTE_GBAS;
|
||||
|
||||
} // namespace Config
|
||||
|
|
|
@ -133,6 +133,11 @@ public:
|
|||
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
|
||||
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_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()))
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -33,12 +33,18 @@
|
|||
#include "Common/Version.h"
|
||||
|
||||
#include "Core/ActionReplay.h"
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Config/NetplaySettings.h"
|
||||
#include "Core/Config/SessionSettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/GeckoCode.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/GCPad.h"
|
||||
#include "Core/HW/SI/SI.h"
|
||||
#include "Core/HW/SI/SI_Device.h"
|
||||
#include "Core/HW/SI/SI_DeviceGCController.h"
|
||||
|
@ -71,7 +77,7 @@ static std::mutex crit_netplay_client;
|
|||
static NetPlayClient* netplay_client = nullptr;
|
||||
static std::unique_ptr<IOS::HLE::FS::FileSystem> s_wii_sync_fs;
|
||||
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
|
||||
NetPlayClient::~NetPlayClient()
|
||||
|
@ -463,6 +469,35 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
|||
}
|
||||
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:
|
||||
{
|
||||
for (PlayerId& mapping : m_wiimote_map)
|
||||
|
@ -482,8 +517,12 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
|||
packet >> map;
|
||||
|
||||
GCPadStatus pad;
|
||||
packet >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >>
|
||||
pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
||||
packet >> 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;
|
||||
}
|
||||
|
||||
// Trusting server for good map value (>=0 && <4)
|
||||
// add to pad buffer
|
||||
|
@ -501,8 +540,12 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
|||
packet >> map;
|
||||
|
||||
GCPadStatus pad;
|
||||
packet >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >>
|
||||
pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
||||
packet >> 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;
|
||||
}
|
||||
|
||||
// Trusting server for good map value (>=0 && <4)
|
||||
// write to last status
|
||||
|
@ -602,14 +645,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
|||
// update gui
|
||||
m_dialog->OnMsgChangeGame(m_selected_game, netplay_name);
|
||||
|
||||
sf::Packet game_status_packet;
|
||||
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);
|
||||
SendGameStatus();
|
||||
|
||||
sf::Packet client_capabilities_packet;
|
||||
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_UseFMA;
|
||||
packet >> m_net_settings.m_HideRemoteGBAs;
|
||||
|
||||
m_net_settings.m_IsHosting = m_local_player->IsHost();
|
||||
m_net_settings.m_HostInputAuthority = m_host_input_authority;
|
||||
|
@ -1055,6 +1092,29 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
|||
}
|
||||
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:
|
||||
PanicAlertFmtT("Unknown SYNC_SAVE_DATA message received with id: {0}", sub_id);
|
||||
break;
|
||||
|
@ -1411,26 +1471,13 @@ void NetPlayClient::GetPlayerList(std::string& list, std::vector<int>& pid_list)
|
|||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
enumerate_player_controller_mappings(m_wiimote_map, player);
|
||||
|
||||
ss << " |\nPing: " << player.ping << "ms\n";
|
||||
ss << "Ping: " << player.ping << "ms\n";
|
||||
ss << "Status: ";
|
||||
|
||||
switch (player.game_status)
|
||||
|
@ -1492,8 +1539,12 @@ void NetPlayClient::AddPadStateToPacket(const int in_game_pad, const GCPadStatus
|
|||
sf::Packet& packet)
|
||||
{
|
||||
packet << static_cast<PadIndex>(in_game_pad);
|
||||
packet << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX
|
||||
<< pad.substickY << pad.triggerLeft << pad.triggerRight << pad.isConnected;
|
||||
packet << pad.button;
|
||||
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
|
||||
|
@ -1648,11 +1699,13 @@ void NetPlayClient::UpdateDevices()
|
|||
|
||||
for (auto player_id : m_pad_map)
|
||||
{
|
||||
// Use local controller types for local controllers if they are compatible
|
||||
// Only GCController-like controllers are supported, GBA and similar
|
||||
// exotic devices are not supported on netplay.
|
||||
if (player_id == m_local_player->pid)
|
||||
if (m_gba_config[pad].enabled && player_id > 0)
|
||||
{
|
||||
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]))
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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)
|
||||
{
|
||||
|
@ -2234,6 +2288,26 @@ bool NetPlayClient::IsLocalPlayer(const PlayerId pid) const
|
|||
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()
|
||||
{
|
||||
std::lock_guard lk(crit_netplay_client);
|
||||
|
@ -2309,6 +2383,11 @@ const PadMappingArray& NetPlayClient::GetPadMapping() const
|
|||
return m_pad_map;
|
||||
}
|
||||
|
||||
const GBAConfigArray& NetPlayClient::GetGBAConfig() const
|
||||
{
|
||||
return m_gba_config;
|
||||
}
|
||||
|
||||
const PadMappingArray& NetPlayClient::GetWiimoteMapping() const
|
||||
{
|
||||
return m_wiimote_map;
|
||||
|
@ -2325,6 +2404,32 @@ SyncIdentifier NetPlayClient::GetSDCardIdentifier()
|
|||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
std::lock_guard lk(crit_netplay_client);
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
|
||||
virtual void OnMsgChangeGame(const SyncIdentifier& sync_identifier,
|
||||
const std::string& netplay_name) = 0;
|
||||
virtual void OnMsgChangeGBARom(int pad, const NetPlay::GBAConfig& config) = 0;
|
||||
virtual void OnMsgStartGame() = 0;
|
||||
virtual void OnMsgStopGame() = 0;
|
||||
virtual void OnMsgPowerButton() = 0;
|
||||
|
@ -62,6 +63,8 @@ public:
|
|||
virtual std::shared_ptr<const UICommon::GameFile>
|
||||
FindGameFile(const SyncIdentifier& sync_identifier,
|
||||
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 SetMD5Progress(int pid, int progress) = 0;
|
||||
virtual void SetMD5Result(int pid, const std::string& result) = 0;
|
||||
|
@ -139,6 +142,7 @@ public:
|
|||
bool DoAllPlayersHaveGame();
|
||||
|
||||
const PadMappingArray& GetPadMapping() const;
|
||||
const GBAConfigArray& GetGBAConfig() const;
|
||||
const PadMappingArray& GetWiimoteMapping() const;
|
||||
|
||||
void AdjustPadBufferSize(unsigned int size);
|
||||
|
@ -199,8 +203,9 @@ protected:
|
|||
|
||||
u32 m_current_game = 0;
|
||||
|
||||
PadMappingArray m_pad_map;
|
||||
PadMappingArray m_wiimote_map;
|
||||
PadMappingArray m_pad_map{};
|
||||
GBAConfigArray m_gba_config{};
|
||||
PadMappingArray m_wiimote_map{};
|
||||
|
||||
bool m_is_recording = false;
|
||||
|
||||
|
@ -231,6 +236,7 @@ private:
|
|||
void Send(const sf::Packet& packet, u8 channel_id = DEFAULT_CHANNEL);
|
||||
void Disconnect();
|
||||
bool Connect();
|
||||
void SendGameStatus();
|
||||
void ComputeMD5(const SyncIdentifier& sync_identifier);
|
||||
void DisplayPlayersPing();
|
||||
u32 GetPlayersMaxPing() const;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
@ -97,10 +98,12 @@ struct NetSettings
|
|||
std::array<int, 4> m_WiimoteExtension;
|
||||
bool m_GolfMode;
|
||||
bool m_UseFMA;
|
||||
bool m_HideRemoteGBAs;
|
||||
|
||||
// These aren't sent over the network directly
|
||||
bool m_IsHosting;
|
||||
bool m_HostInputAuthority;
|
||||
std::array<std::string, 4> m_GBARomPaths;
|
||||
};
|
||||
|
||||
struct NetTraversalConfig
|
||||
|
@ -136,6 +139,7 @@ enum
|
|||
NP_MSG_PAD_MAPPING = 0x61,
|
||||
NP_MSG_PAD_BUFFER = 0x62,
|
||||
NP_MSG_PAD_HOST_DATA = 0x63,
|
||||
NP_MSG_GBA_CONFIG = 0x64,
|
||||
|
||||
NP_MSG_WIIMOTE_DATA = 0x70,
|
||||
NP_MSG_WIIMOTE_MAPPING = 0x71,
|
||||
|
@ -191,7 +195,8 @@ enum
|
|||
SYNC_SAVE_DATA_FAILURE = 2,
|
||||
SYNC_SAVE_DATA_RAW = 3,
|
||||
SYNC_SAVE_DATA_GCI = 4,
|
||||
SYNC_SAVE_DATA_WII = 5
|
||||
SYNC_SAVE_DATA_WII = 5,
|
||||
SYNC_SAVE_DATA_GBA = 6
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -225,7 +230,26 @@ using PlayerId = u8;
|
|||
using FrameNum = u32;
|
||||
using PadIndex = s8;
|
||||
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();
|
||||
// Precondition: A netplay client instance must be present. In other words,
|
||||
// IsNetPlayRunning() must be true before calling this.
|
||||
|
@ -238,4 +262,6 @@ void SetSIPollBatching(bool state);
|
|||
void SendPowerButtonEvent();
|
||||
bool IsSyncingAllWiiSaves();
|
||||
void SetupWiimotes();
|
||||
std::string GetGBASavePath(int pad_num);
|
||||
PadDetails GetPadDetails(int pad_num);
|
||||
} // namespace NetPlay
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
#include "Core/ConfigManager.h"
|
||||
#include "Core/GeckoCode.h"
|
||||
#include "Core/GeckoCodeConfig.h"
|
||||
#ifdef HAS_LIBMGBA
|
||||
#include "Core/HW/GBACore.h"
|
||||
#endif
|
||||
#include "Core/HW/GCMemcard/GCMemcard.h"
|
||||
#include "Core/HW/GCMemcard/GCMemcardDirectory.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_gba_config.fill({});
|
||||
m_wiimote_map.fill(0);
|
||||
|
||||
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);
|
||||
m_players.emplace(*PeerPlayerId(player.socket), std::move(player));
|
||||
UpdatePadMapping(); // sync pad mappings with everyone
|
||||
UpdateGBAConfig();
|
||||
UpdateWiimoteMapping();
|
||||
}
|
||||
|
||||
|
@ -530,12 +535,14 @@ unsigned int NetPlayServer::OnDisconnect(const Client& player)
|
|||
// alert other players of disconnect
|
||||
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();
|
||||
UpdateGBAConfig();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -557,6 +564,11 @@ PadMappingArray NetPlayServer::GetPadMapping() const
|
|||
return m_pad_map;
|
||||
}
|
||||
|
||||
GBAConfigArray NetPlayServer::GetGBAConfig() const
|
||||
{
|
||||
return m_gba_config;
|
||||
}
|
||||
|
||||
PadMappingArray NetPlayServer::GetWiimoteMapping() const
|
||||
{
|
||||
return m_wiimote_map;
|
||||
|
@ -569,6 +581,26 @@ void NetPlayServer::SetPadMapping(const PadMappingArray& mappings)
|
|||
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
|
||||
void NetPlayServer::SetWiimoteMapping(const PadMappingArray& mappings)
|
||||
{
|
||||
|
@ -588,6 +620,20 @@ void NetPlayServer::UpdatePadMapping()
|
|||
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
|
||||
void NetPlayServer::UpdateWiimoteMapping()
|
||||
{
|
||||
|
@ -751,12 +797,16 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
|
|||
}
|
||||
|
||||
GCPadStatus pad;
|
||||
packet >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >>
|
||||
pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
||||
packet >> pad.button;
|
||||
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
|
||||
<< pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight
|
||||
<< pad.isConnected;
|
||||
spac << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX
|
||||
<< pad.substickY << pad.triggerLeft << pad.triggerRight << pad.isConnected;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_host_input_authority)
|
||||
|
@ -787,12 +837,16 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
|
|||
packet >> map;
|
||||
|
||||
GCPadStatus pad;
|
||||
packet >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >>
|
||||
pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
||||
packet >> pad.button;
|
||||
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
|
||||
<< pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight
|
||||
<< pad.isConnected;
|
||||
spac << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX
|
||||
<< pad.substickY << pad.triggerLeft << pad.triggerRight << pad.isConnected;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
settings.m_GolfMode = Config::Get(Config::NETPLAY_NETWORK_MODE) == "golf";
|
||||
settings.m_UseFMA = DoAllPlayersHaveHardwareFMA();
|
||||
settings.m_HideRemoteGBAs = Config::Get(Config::NETPLAY_HIDE_REMOTE_GBAS);
|
||||
|
||||
// Unload GameINI to restore things to normal
|
||||
Config::RemoveLayer(Config::LayerType::GlobalGame);
|
||||
|
@ -1501,6 +1556,7 @@ bool NetPlayServer::StartGame()
|
|||
|
||||
spac << m_settings.m_GolfMode;
|
||||
spac << m_settings.m_UseFMA;
|
||||
spac << m_settings.m_HideRemoteGBAs;
|
||||
|
||||
SendAsyncToClients(std::move(spac));
|
||||
|
||||
|
@ -1556,6 +1612,12 @@ bool NetPlayServer::SyncSaveData()
|
|||
save_count++;
|
||||
}
|
||||
|
||||
for (const auto& config : m_gba_config)
|
||||
{
|
||||
if (config.enabled && config.has_rom)
|
||||
save_count++;
|
||||
}
|
||||
|
||||
{
|
||||
sf::Packet pac;
|
||||
pac << static_cast<MessageId>(NP_MSG_SYNC_SAVE_DATA);
|
||||
|
@ -1758,6 +1820,36 @@ bool NetPlayServer::SyncSaveData()
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,9 @@ public:
|
|||
PadMappingArray GetPadMapping() const;
|
||||
void SetPadMapping(const PadMappingArray& mappings);
|
||||
|
||||
GBAConfigArray GetGBAConfig() const;
|
||||
void SetGBAConfig(const GBAConfigArray& configs, bool update_rom);
|
||||
|
||||
PadMappingArray GetWiimoteMapping() const;
|
||||
void SetWiimoteMapping(const PadMappingArray& mappings);
|
||||
|
||||
|
@ -134,6 +137,7 @@ private:
|
|||
void OnConnectReady(ENetAddress) override {}
|
||||
void OnConnectFailed(TraversalConnectFailedReason) override {}
|
||||
void UpdatePadMapping();
|
||||
void UpdateGBAConfig();
|
||||
void UpdateWiimoteMapping();
|
||||
std::vector<std::pair<std::string, std::string>> GetInterfaceListInternal() const;
|
||||
void ChunkedDataThreadFunc();
|
||||
|
@ -153,6 +157,7 @@ private:
|
|||
u32 m_current_game = 0;
|
||||
unsigned int m_target_buffer_size = 0;
|
||||
PadMappingArray m_pad_map;
|
||||
GBAConfigArray m_gba_config;
|
||||
PadMappingArray m_wiimote_map;
|
||||
unsigned int m_save_data_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)
|
||||
{
|
||||
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());
|
||||
setAcceptDrops(true);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QComboBox>
|
||||
#include <QFileDialog>
|
||||
#include <QGridLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QHeaderView>
|
||||
|
@ -35,6 +36,9 @@
|
|||
#include "Core/Config/NetplaySettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#ifdef HAS_LIBMGBA
|
||||
#include "Core/HW/GBACore.h"
|
||||
#endif
|
||||
#include "Core/NetPlayServer.h"
|
||||
#include "Core/SyncIdentifier.h"
|
||||
|
||||
|
@ -47,6 +51,7 @@
|
|||
#include "DolphinQt/QtUtils/RunOnObject.h"
|
||||
#include "DolphinQt/Resources.h"
|
||||
#include "DolphinQt/Settings.h"
|
||||
#include "DolphinQt/Settings/GameCubePane.h"
|
||||
|
||||
#include "UICommon/DiscordPresence.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
|
@ -171,6 +176,8 @@ void NetPlayDialog::CreateMainLayout()
|
|||
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->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->setAutoDefault(false);
|
||||
|
@ -279,6 +286,7 @@ void NetPlayDialog::ConnectWidgets()
|
|||
m_pad_mapping->exec();
|
||||
|
||||
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());
|
||||
});
|
||||
|
||||
|
@ -365,6 +373,7 @@ void NetPlayDialog::ConnectWidgets()
|
|||
connect(m_golf_mode_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_hide_remote_gbas_action, &QAction::toggled, this, &NetPlayDialog::SaveSettings);
|
||||
}
|
||||
|
||||
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_network_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_kick_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")});
|
||||
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{
|
||||
{NetPlay::SyncIdentifierComparison::SameGame, tr("OK")},
|
||||
{NetPlay::SyncIdentifierComparison::DifferentVersion, tr("Wrong Version")},
|
||||
|
@ -599,9 +599,9 @@ void NetPlayDialog::UpdateGUI()
|
|||
player_status.at(p->game_status) :
|
||||
QStringLiteral("?"));
|
||||
auto* ping_item = new QTableWidgetItem(QStringLiteral("%1 ms").arg(p->ping));
|
||||
auto* mapping_item = new QTableWidgetItem(
|
||||
QString::fromStdString(get_mapping_string(p, client->GetPadMapping()) +
|
||||
get_mapping_string(p, client->GetWiimoteMapping())));
|
||||
auto* mapping_item =
|
||||
new QTableWidgetItem(QString::fromStdString(NetPlay::GetPlayerMappingString(
|
||||
p->pid, client->GetPadMapping(), client->GetGBAConfig(), client->GetWiimoteMapping())));
|
||||
auto* revision_item = new QTableWidgetItem(QString::fromStdString(p->revision));
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
QueueOnObject(this, [this, running] { SetOptionsEnabled(!running); });
|
||||
|
@ -976,6 +990,51 @@ NetPlayDialog::FindGameFile(const NetPlay::SyncIdentifier& sync_identifier,
|
|||
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()
|
||||
{
|
||||
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 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 hide_remote_gbas = Config::Get(Config::NETPLAY_HIDE_REMOTE_GBAS);
|
||||
|
||||
m_buffer_size_box->setValue(buffer_size);
|
||||
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_sync_all_wii_saves_action->setChecked(sync_all_wii_saves);
|
||||
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);
|
||||
|
||||
|
@ -1036,6 +1097,7 @@ void NetPlayDialog::SaveSettings()
|
|||
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_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;
|
||||
if (m_fixed_delay_action->isChecked())
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
|
||||
void OnMsgChangeGame(const NetPlay::SyncIdentifier& sync_identifier,
|
||||
const std::string& netplay_name) override;
|
||||
void OnMsgChangeGBARom(int pad, const NetPlay::GBAConfig& config) override;
|
||||
void OnMsgStartGame() override;
|
||||
void OnMsgStopGame() override;
|
||||
void OnMsgPowerButton() override;
|
||||
|
@ -68,6 +69,8 @@ public:
|
|||
std::shared_ptr<const UICommon::GameFile>
|
||||
FindGameFile(const NetPlay::SyncIdentifier& sync_identifier,
|
||||
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 SaveSettings();
|
||||
|
@ -138,6 +141,7 @@ private:
|
|||
QAction* m_golf_mode_action;
|
||||
QAction* m_golf_mode_overlay_action;
|
||||
QAction* m_fixed_delay_action;
|
||||
QAction* m_hide_remote_gbas_action;
|
||||
QPushButton* m_quit_button;
|
||||
QSplitter* m_splitter;
|
||||
QActionGroup* m_network_mode_group;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "DolphinQt/NetPlay/PadMappingDialog.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
|
@ -31,15 +32,19 @@ void PadMappingDialog::CreateWidgets()
|
|||
for (unsigned int i = 0; i < m_wii_boxes.size(); i++)
|
||||
{
|
||||
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_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(new QLabel(tr("Wii Remote %1").arg(i + 1)), 2, i);
|
||||
m_main_layout->addWidget(m_wii_boxes[i], 3, i);
|
||||
#ifdef HAS_LIBMGBA
|
||||
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);
|
||||
}
|
||||
|
@ -55,6 +60,11 @@ void PadMappingDialog::ConnectWidgets()
|
|||
&PadMappingDialog::OnMappingChanged);
|
||||
}
|
||||
}
|
||||
for (const auto& checkbox : m_gba_boxes)
|
||||
{
|
||||
connect(checkbox, qOverload<int>(&QCheckBox::stateChanged), this,
|
||||
&PadMappingDialog::OnMappingChanged);
|
||||
}
|
||||
}
|
||||
|
||||
int PadMappingDialog::exec()
|
||||
|
@ -64,6 +74,7 @@ int PadMappingDialog::exec()
|
|||
// Load Settings
|
||||
m_players = client->GetPlayers();
|
||||
m_pad_mapping = server->GetPadMapping();
|
||||
m_gba_config = server->GetGBAConfig();
|
||||
m_wii_mapping = server->GetWiimoteMapping();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -101,6 +119,11 @@ NetPlay::PadMappingArray PadMappingDialog::GetGCPadArray()
|
|||
return m_pad_mapping;
|
||||
}
|
||||
|
||||
NetPlay::GBAConfigArray PadMappingDialog::GetGBAArray()
|
||||
{
|
||||
return m_gba_config;
|
||||
}
|
||||
|
||||
NetPlay::PadMappingArray PadMappingDialog::GetWiimoteArray()
|
||||
{
|
||||
return m_wii_mapping;
|
||||
|
@ -114,6 +137,7 @@ void PadMappingDialog::OnMappingChanged()
|
|||
int wii_id = m_wii_boxes[i]->currentIndex();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "Core/NetPlayProto.h"
|
||||
|
||||
class QCheckBox;
|
||||
class QGridLayout;
|
||||
class QComboBox;
|
||||
class QDialogButtonBox;
|
||||
|
@ -25,6 +26,7 @@ public:
|
|||
int exec() override;
|
||||
|
||||
NetPlay::PadMappingArray GetGCPadArray();
|
||||
NetPlay::GBAConfigArray GetGBAArray();
|
||||
NetPlay::PadMappingArray GetWiimoteArray();
|
||||
|
||||
private:
|
||||
|
@ -34,10 +36,12 @@ private:
|
|||
void OnMappingChanged();
|
||||
|
||||
NetPlay::PadMappingArray m_pad_mapping;
|
||||
NetPlay::GBAConfigArray m_gba_config;
|
||||
NetPlay::PadMappingArray m_wii_mapping;
|
||||
|
||||
QGridLayout* m_main_layout;
|
||||
std::array<QComboBox*, 4> m_gc_boxes;
|
||||
std::array<QCheckBox*, 4> m_gba_boxes;
|
||||
std::array<QComboBox*, 4> m_wii_boxes;
|
||||
std::vector<const NetPlay::Player*> m_players;
|
||||
QDialogButtonBox* m_button_box;
|
||||
|
|
|
@ -542,6 +542,10 @@ void GameCubePane::SaveSettings()
|
|||
Config::SetBaseOrCurrent(Config::MAIN_GBA_ROM_PATHS[i],
|
||||
m_gba_rom_edits[i]->text().toStdString());
|
||||
}
|
||||
|
||||
auto server = Settings::Instance().GetNetPlayServer();
|
||||
if (server)
|
||||
server->SetGBAConfig(server->GetGBAConfig(), true);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue