123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- // Copyright 2013 Dolphin Emulator Project
- // SPDX-License-Identifier: GPL-2.0-or-later
- #pragma once
- #include <SFML/Network/Packet.hpp>
- #include <map>
- #include <memory>
- #include <mutex>
- #include <optional>
- #include <queue>
- #include <sstream>
- #include <thread>
- #include <unordered_map>
- #include <unordered_set>
- #include <utility>
- #include "Common/Event.h"
- #include "Common/QoSSession.h"
- #include "Common/SPSCQueue.h"
- #include "Common/Timer.h"
- #include "Common/TraversalClient.h"
- #include "Core/NetPlayProto.h"
- #include "Core/SyncIdentifier.h"
- #include "InputCommon/GCPadStatus.h"
- #include "UICommon/NetPlayIndex.h"
- namespace NetPlay
- {
- class NetPlayUI;
- struct SaveSyncInfo;
- class NetPlayServer : public Common::TraversalClientClient
- {
- public:
- void ThreadFunc();
- void SendAsync(sf::Packet&& packet, PlayerId pid, u8 channel_id = DEFAULT_CHANNEL);
- void SendAsyncToClients(sf::Packet&& packet, PlayerId skip_pid = 0,
- u8 channel_id = DEFAULT_CHANNEL);
- void SendChunked(sf::Packet&& packet, PlayerId pid, const std::string& title = "");
- void SendChunkedToClients(sf::Packet&& packet, PlayerId skip_pid = 0,
- const std::string& title = "");
- NetPlayServer(u16 port, bool forward_port, NetPlayUI* dialog,
- const NetTraversalConfig& traversal_config);
- ~NetPlayServer();
- bool ChangeGame(const SyncIdentifier& sync_identifier, const std::string& netplay_name);
- bool ComputeGameDigest(const SyncIdentifier& sync_identifier);
- bool AbortGameDigest();
- void SendChatMessage(const std::string& msg);
- bool DoAllPlayersHaveIPLDump() const;
- bool DoAllPlayersHaveHardwareFMA() const;
- bool StartGame();
- bool RequestStartGame();
- void AbortGameStart();
- 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);
- void AdjustPadBufferSize(unsigned int size);
- void SetHostInputAuthority(bool enable);
- void KickPlayer(PlayerId player);
- u16 GetPort() const;
- std::unordered_set<std::string> GetInterfaceSet() const;
- std::string GetInterfaceHost(const std::string& inter) const;
- bool is_connected = false;
- private:
- class Client
- {
- public:
- PlayerId pid{};
- std::string name;
- std::string revision;
- SyncIdentifierComparison game_status = SyncIdentifierComparison::Unknown;
- bool has_ipl_dump = false;
- bool has_hardware_fma = false;
- ENetPeer* socket = nullptr;
- u32 ping = 0;
- u32 current_game = 0;
- Common::QoSSession qos_session;
- bool operator==(const Client& other) const { return this == &other; }
- bool IsHost() const { return pid == 1; }
- };
- enum class TargetMode
- {
- Only,
- AllExcept
- };
- struct AsyncQueueEntry
- {
- sf::Packet packet;
- PlayerId target_pid{};
- TargetMode target_mode{};
- u8 channel_id = 0;
- };
- struct ChunkedDataQueueEntry
- {
- sf::Packet packet;
- PlayerId target_pid{};
- TargetMode target_mode{};
- std::string title;
- };
- bool SetupNetSettings();
- std::optional<SaveSyncInfo> CollectSaveSyncInfo();
- bool SyncSaveData(const SaveSyncInfo& sync_info);
- bool SyncCodes();
- void CheckSyncAndStartGame();
- u64 GetInitialNetPlayRTC() const;
- template <typename... Data>
- void SendResponseToPlayer(const Client& player, const MessageID message_id,
- Data&&... data_to_send);
- template <typename... Data>
- void SendResponseToAllPlayers(const MessageID message_id, Data&&... data_to_send);
- void SendToClients(const sf::Packet& packet, PlayerId skip_pid = 0,
- u8 channel_id = DEFAULT_CHANNEL);
- void Send(ENetPeer* socket, const sf::Packet& packet, u8 channel_id = DEFAULT_CHANNEL);
- ConnectionError OnConnect(ENetPeer* socket, sf::Packet& received_packet);
- unsigned int OnDisconnect(const Client& player);
- unsigned int OnData(sf::Packet& packet, Client& player);
- void OnTraversalStateChanged() override;
- void OnConnectReady(ENetAddress) override {}
- void OnConnectFailed(Common::TraversalConnectFailedReason) override {}
- void OnTtlDetermined(u8 ttl) override;
- void UpdatePadMapping();
- void UpdateGBAConfig();
- void UpdateWiimoteMapping();
- std::vector<std::pair<std::string, std::string>> GetInterfaceListInternal() const;
- void ChunkedDataThreadFunc();
- void ChunkedDataSend(sf::Packet&& packet, PlayerId pid, const TargetMode target_mode);
- void ChunkedDataAbort();
- void SetupIndex();
- bool PlayerHasControllerMapped(PlayerId pid) const;
- // pulled from OnConnect()
- void AssignNewUserAPad(const Client& player);
- // pulled from OnConnect()
- // returns the PID given
- PlayerId GiveFirstAvailableIDTo(ENetPeer* player);
- NetSettings m_settings;
- bool m_is_running = false;
- bool m_do_loop = false;
- Common::Timer m_ping_timer;
- u32 m_ping_key = 0;
- bool m_update_pings = false;
- 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;
- bool m_saves_synced = true;
- bool m_codes_synced = true;
- bool m_start_pending = false;
- bool m_host_input_authority = false;
- PlayerId m_current_golfer = 1;
- PlayerId m_pending_golfer = 0;
- std::map<PlayerId, Client> m_players;
- std::unordered_map<u32, std::vector<std::pair<PlayerId, u64>>> m_timebase_by_frame;
- bool m_desync_detected = false;
- struct
- {
- std::recursive_mutex game;
- // lock order
- std::recursive_mutex players;
- std::recursive_mutex async_queue_write;
- std::recursive_mutex chunked_data_queue_write;
- } m_crit;
- Common::SPSCQueue<AsyncQueueEntry, false> m_async_queue;
- Common::SPSCQueue<ChunkedDataQueueEntry, false> m_chunked_data_queue;
- SyncIdentifier m_selected_game_identifier;
- std::string m_selected_game_name;
- std::thread m_thread;
- Common::Event m_chunked_data_event;
- Common::Event m_chunked_data_complete_event;
- std::thread m_chunked_data_thread;
- u32 m_next_chunked_data_id = 0;
- std::unordered_map<u32, unsigned int> m_chunked_data_complete_count;
- bool m_abort_chunked_data = false;
- ENetHost* m_server = nullptr;
- Common::TraversalClient* m_traversal_client = nullptr;
- NetPlayUI* m_dialog = nullptr;
- NetPlayIndex m_index;
- };
- } // namespace NetPlay
|