diff options
| author | iwubcode <iwubcode@users.noreply.github.com> | 2020-05-09 15:44:45 -0500 |
|---|---|---|
| committer | iwubcode <iwubcode@users.noreply.github.com> | 2020-07-17 14:53:39 -0500 |
| commit | 58aa0150e1d3d391d5fd4e04ab402afb10a60fcc (patch) | |
| tree | adcca627f92d26bf324eea6e8d73dbaaf149aa1d /Source/Core/InputCommon/ControllerInterface | |
| parent | a98df567b11758c9581b23dc72cb1ee9afaf79ce (diff) | |
DolphinQt / InputCommon: Support multiple DSU servers
Diffstat (limited to 'Source/Core/InputCommon/ControllerInterface')
3 files changed, 144 insertions, 87 deletions
diff --git a/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPClient.cpp b/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPClient.cpp index c398225bfe..837be2c3df 100644 --- a/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPClient.cpp +++ b/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPClient.cpp @@ -12,6 +12,7 @@ #include <SFML/Network/SocketSelector.hpp> #include <SFML/Network/UdpSocket.hpp> +#include <fmt/format.h> #include "Common/Config/Config.h" #include "Common/Flag.h" @@ -19,6 +20,7 @@ #include "Common/MathUtil.h" #include "Common/Matrix.h" #include "Common/Random.h" +#include "Common/StringUtil.h" #include "Common/Thread.h" #include "Core/CoreTiming.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" @@ -28,15 +30,10 @@ namespace ciface::DualShockUDPClient { namespace Settings { -constexpr char DEFAULT_SERVER_ADDRESS[] = "127.0.0.1"; -constexpr u16 DEFAULT_SERVER_PORT = 26760; - -const Config::Info<bool> SERVER_ENABLED{{Config::System::DualShockUDPClient, "Server", "Enabled"}, - false}; -const Config::Info<std::string> SERVER_ADDRESS{ - {Config::System::DualShockUDPClient, "Server", "IPAddress"}, DEFAULT_SERVER_ADDRESS}; -const Config::Info<int> SERVER_PORT{{Config::System::DualShockUDPClient, "Server", "Port"}, - DEFAULT_SERVER_PORT}; +const Config::Info<std::string> SERVERS{{Config::System::DualShockUDPClient, "Server", "Entries"}, + ""}; +const Config::Info<bool> SERVERS_ENABLED{{Config::System::DualShockUDPClient, "Server", "Enabled"}, + false}; } // namespace Settings // Clock type used for querying timeframes @@ -130,14 +127,14 @@ private: public: void UpdateInput() override; - Device(Proto::DsModel model, int index); + Device(std::string name, int index, std::string server_address, u16 server_port); std::string GetName() const final override; std::string GetSource() const final override; std::optional<int> GetPreferredId() const final override; private: - const Proto::DsModel m_model; + const std::string m_name; const int m_index; u32 m_client_uid = Common::Random::GenerateValue<u32>(); sf::UdpSocket m_socket; @@ -147,6 +144,8 @@ private: bool m_prev_touch_valid = false; int m_touch_x = 0; int m_touch_y = 0; + std::string m_server_address; + u16 m_server_port; }; using MathUtil::GRAVITY_ACCELERATION; @@ -155,16 +154,40 @@ constexpr auto SERVER_LISTPORTS_INTERVAL = std::chrono::seconds{1}; constexpr int TOUCH_X_AXIS_MAX = 1000; constexpr int TOUCH_Y_AXIS_MAX = 500; -static bool s_server_enabled; -static std::string s_server_address; -static u16 s_server_port; +struct Server +{ + Server(std::string description, std::string address, u16 port) + : m_description{std::move(description)}, m_address{std::move(address)}, m_port{port} + { + } + Server(const Server&) = delete; + Server(Server&& other) noexcept + { + m_description = std::move(other.m_description); + m_address = std::move(other.m_address); + m_port = other.m_port; + m_port_info = std::move(other.m_port_info); + } + + Server& operator=(const Server&) = delete; + Server& operator=(Server&&) = delete; + + ~Server() = default; + + std::string m_description; + std::string m_address; + u16 m_port; + std::mutex m_port_info_mutex; + std::array<Proto::MessageType::PortInfo, Proto::PORT_COUNT> m_port_info; + sf::UdpSocket m_socket; +}; + +static bool s_servers_enabled; +static std::vector<Server> s_servers; static u32 s_client_uid; static SteadyClock::time_point s_next_listports; static std::thread s_hotplug_thread; static Common::Flag s_hotplug_thread_running; -static std::mutex s_port_info_mutex; -static std::array<Proto::MessageType::PortInfo, Proto::PORT_COUNT> s_port_info; -static sf::UdpSocket s_socket; static bool IsSameController(const Proto::MessageType::PortInfo& a, const Proto::MessageType::PortInfo& b) @@ -198,39 +221,48 @@ static void HotplugThreadFunc() { s_next_listports = now + SERVER_LISTPORTS_INTERVAL; - // Request info on the four controller ports - Proto::Message<Proto::MessageType::ListPorts> msg(s_client_uid); - auto& list_ports = msg.m_message; - list_ports.pad_request_count = 4; - list_ports.pad_id = {0, 1, 2, 3}; - msg.Finish(); - if (s_socket.send(&list_ports, sizeof list_ports, s_server_address, s_server_port) != - sf::Socket::Status::Done) - ERROR_LOG(SERIALINTERFACE, "DualShockUDPClient HotplugThreadFunc send failed"); + for (auto& server : s_servers) + { + // Request info on the four controller ports + Proto::Message<Proto::MessageType::ListPorts> msg(s_client_uid); + auto& list_ports = msg.m_message; + list_ports.pad_request_count = 4; + list_ports.pad_id = {0, 1, 2, 3}; + msg.Finish(); + if (server.m_socket.send(&list_ports, sizeof list_ports, server.m_address, server.m_port) != + sf::Socket::Status::Done) + { + ERROR_LOG(SERIALINTERFACE, "DualShockUDPClient HotplugThreadFunc send failed"); + } + } } - // Receive controller port info - using namespace std::chrono; - using namespace std::chrono_literals; - Proto::Message<Proto::MessageType::FromServer> msg; - const auto timeout = s_next_listports - SteadyClock::now(); - // ReceiveWithTimeout treats a timeout of zero as infinite timeout, which we don't want - const auto timeout_ms = std::max(duration_cast<milliseconds>(timeout), 1ms); - std::size_t received_bytes; - sf::IpAddress sender; - u16 port; - if (ReceiveWithTimeout(s_socket, &msg, sizeof(msg), received_bytes, sender, port, - sf::milliseconds(timeout_ms.count())) == sf::Socket::Status::Done) + for (auto& server : s_servers) { - if (auto port_info = msg.CheckAndCastTo<Proto::MessageType::PortInfo>()) + // Receive controller port info + using namespace std::chrono; + using namespace std::chrono_literals; + Proto::Message<Proto::MessageType::FromServer> msg; + const auto timeout = s_next_listports - SteadyClock::now(); + // ReceiveWithTimeout treats a timeout of zero as infinite timeout, which we don't want + const auto timeout_ms = std::max(duration_cast<milliseconds>(timeout), 1ms); + std::size_t received_bytes; + sf::IpAddress sender; + u16 port; + if (ReceiveWithTimeout(server.m_socket, &msg, sizeof(msg), received_bytes, sender, port, + sf::milliseconds(timeout_ms.count())) == sf::Socket::Status::Done) { - const bool port_changed = !IsSameController(*port_info, s_port_info[port_info->pad_id]); + if (auto port_info = msg.CheckAndCastTo<Proto::MessageType::PortInfo>()) { - std::lock_guard lock{s_port_info_mutex}; - s_port_info[port_info->pad_id] = *port_info; + const bool port_changed = + !IsSameController(*port_info, server.m_port_info[port_info->pad_id]); + { + std::lock_guard lock{server.m_port_info_mutex}; + server.m_port_info[port_info->pad_id] = *port_info; + } + if (port_changed) + PopulateDevices(); } - if (port_changed) - PopulateDevices(); } } } @@ -258,7 +290,10 @@ static void StopHotplugThread() return; } - s_socket.unbind(); // interrupt blocking socket + for (auto& server : s_servers) + { + server.m_socket.unbind(); // interrupt blocking socket + } s_hotplug_thread.join(); } @@ -270,29 +305,56 @@ static void Restart() s_client_uid = Common::Random::GenerateValue<u32>(); s_next_listports = std::chrono::steady_clock::time_point::min(); - for (size_t port_index = 0; port_index < s_port_info.size(); port_index++) + for (auto& server : s_servers) { - s_port_info[port_index] = {}; - s_port_info[port_index].pad_id = static_cast<u8>(port_index); + for (size_t port_index = 0; port_index < server.m_port_info.size(); port_index++) + { + server.m_port_info[port_index] = {}; + server.m_port_info[port_index].pad_id = static_cast<u8>(port_index); + } } PopulateDevices(); // remove devices - if (s_server_enabled) + if (s_servers_enabled && !s_servers.empty()) StartHotplugThread(); } static void ConfigChanged() { - bool server_enabled = Config::Get(Settings::SERVER_ENABLED); - std::string server_address = Config::Get(Settings::SERVER_ADDRESS); - u16 server_port = Config::Get(Settings::SERVER_PORT); - if (server_enabled != s_server_enabled || server_address != s_server_address || - server_port != s_server_port) + const bool servers_enabled = Config::Get(Settings::SERVERS_ENABLED); + const std::string servers_setting = Config::Get(Settings::SERVERS); + + std::string new_servers_setting; + for (const auto& server : s_servers) + { + new_servers_setting += + fmt::format("{}:{}:{};", server.m_description, server.m_address, server.m_port); + } + + if (servers_enabled != s_servers_enabled || servers_setting != new_servers_setting) { - s_server_enabled = server_enabled; - s_server_address = server_address; - s_server_port = server_port; + s_servers_enabled = servers_enabled; + s_servers.clear(); + + const auto server_details = SplitString(servers_setting, ';'); + for (const auto& server_detail : server_details) + { + const auto server_info = SplitString(server_detail, ':'); + if (server_info.size() < 3) + continue; + + const std::string description = server_info[0]; + const std::string server_address = server_info[1]; + const auto port = std::stoi(server_info[2]); + if (port >= std::numeric_limits<u16>::max()) + { + continue; + } + u16 server_port = static_cast<u16>(port); + + s_servers.emplace_back(description, server_address, server_port); + } Restart(); } } @@ -306,18 +368,21 @@ void PopulateDevices() { INFO_LOG(SERIALINTERFACE, "DualShockUDPClient PopulateDevices"); - g_controller_interface.RemoveDevice( - [](const auto* dev) { return dev->GetSource() == "DSUClient"; }); - - std::lock_guard lock{s_port_info_mutex}; - for (size_t port_index = 0; port_index < s_port_info.size(); port_index++) + for (auto& server : s_servers) { - const Proto::MessageType::PortInfo& port_info = s_port_info[port_index]; - if (port_info.pad_state != Proto::DsState::Connected) - continue; + g_controller_interface.RemoveDevice( + [&server](const auto* dev) { return dev->GetName() == server.m_description; }); + + std::lock_guard lock{server.m_port_info_mutex}; + for (size_t port_index = 0; port_index < server.m_port_info.size(); port_index++) + { + const Proto::MessageType::PortInfo& port_info = server.m_port_info[port_index]; + if (port_info.pad_state != Proto::DsState::Connected) + continue; - g_controller_interface.AddDevice( - std::make_shared<Device>(port_info.model, static_cast<int>(port_index))); + g_controller_interface.AddDevice(std::make_shared<Device>( + server.m_description, static_cast<int>(port_index), server.m_address, server.m_port)); + } } } @@ -326,7 +391,9 @@ void DeInit() StopHotplugThread(); } -Device::Device(Proto::DsModel model, int index) : m_model{model}, m_index{index} +Device::Device(std::string name, int index, std::string server_address, u16 server_port) + : m_name{std::move(name)}, m_index{index}, m_server_address{std::move(server_address)}, + m_server_port{server_port} { m_socket.setBlocking(false); @@ -388,19 +455,7 @@ Device::Device(Proto::DsModel model, int index) : m_model{model}, m_index{index} std::string Device::GetName() const { - switch (m_model) - { - case Proto::DsModel::None: - return "None"; - case Proto::DsModel::DS3: - return "DualShock 3"; - case Proto::DsModel::DS4: - return "DualShock 4"; - case Proto::DsModel::Generic: - return "Generic Gamepad"; - default: - return "Device"; - } + return m_name; } std::string Device::GetSource() const @@ -421,7 +476,7 @@ void Device::UpdateInput() data_req.register_flags = Proto::RegisterFlags::PadID; data_req.pad_id_to_register = m_index; msg.Finish(); - if (m_socket.send(&data_req, sizeof(data_req), s_server_address, s_server_port) != + if (m_socket.send(&data_req, sizeof(data_req), m_server_address, m_server_port) != sf::Socket::Status::Done) ERROR_LOG(SERIALINTERFACE, "DualShockUDPClient UpdateInput send failed"); } diff --git a/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPClient.h b/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPClient.h index 1b51a2e1b9..e7a9057569 100644 --- a/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPClient.h +++ b/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPClient.h @@ -8,11 +8,13 @@ namespace ciface::DualShockUDPClient { +constexpr char DEFAULT_SERVER_ADDRESS[] = "127.0.0.1"; +constexpr u16 DEFAULT_SERVER_PORT = 26760; + namespace Settings { -extern const Config::Info<bool> SERVER_ENABLED; -extern const Config::Info<std::string> SERVER_ADDRESS; -extern const Config::Info<int> SERVER_PORT; +extern const Config::Info<std::string> SERVERS; +extern const Config::Info<bool> SERVERS_ENABLED; } // namespace Settings void Init(); diff --git a/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPProto.h b/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPProto.h index 5e3e9f0dde..97b453a68a 100644 --- a/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPProto.h +++ b/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPProto.h @@ -45,8 +45,8 @@ enum class DsConnection : u8 enum class DsModel : u8 { None = 0, - DS3 = 1, - DS4 = 2, + PartialGyro = 1, + FullGyro = 2, Generic = 3 }; |
