123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502 |
- #include "Core/NetPlayServer.h"
- #include <algorithm>
- #include <chrono>
- #include <cstddef>
- #include <cstdio>
- #include <memory>
- #include <mutex>
- #include <optional>
- #include <string>
- #include <thread>
- #include <type_traits>
- #include <unordered_set>
- #include <utility>
- #include <vector>
- #include <fmt/format.h>
- #include <fmt/ranges.h>
- #include "Common/CommonPaths.h"
- #include "Common/ENet.h"
- #include "Common/FileUtil.h"
- #include "Common/HttpRequest.h"
- #include "Common/Logging/Log.h"
- #include "Common/MsgHandler.h"
- #include "Common/SFMLHelper.h"
- #include "Common/StringUtil.h"
- #include "Common/UPnP.h"
- #include "Common/Version.h"
- #include "Core/ActionReplay.h"
- #include "Core/Boot/Boot.h"
- #include "Core/Config/GraphicsSettings.h"
- #include "Core/Config/MainSettings.h"
- #include "Core/Config/NetplaySettings.h"
- #include "Core/Config/SYSCONFSettings.h"
- #include "Core/Config/SessionSettings.h"
- #include "Core/ConfigLoaders/GameConfigLoader.h"
- #include "Core/ConfigManager.h"
- #include "Core/GeckoCode.h"
- #include "Core/GeckoCodeConfig.h"
- #include "Core/HW/EXI/EXI.h"
- #include "Core/HW/EXI/EXI_Device.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"
- #include "Core/HW/Sram.h"
- #include "Core/HW/WiiSave.h"
- #include "Core/HW/WiiSaveStructs.h"
- #include "Core/HW/WiimoteEmu/DesiredWiimoteState.h"
- #include "Core/HW/WiimoteEmu/WiimoteEmu.h"
- #include "Core/HW/WiimoteReal/WiimoteReal.h"
- #include "Core/IOS/ES/ES.h"
- #include "Core/IOS/FS/FileSystem.h"
- #include "Core/IOS/IOS.h"
- #include "Core/IOS/Uids.h"
- #include "Core/NetPlayClient.h"
- #include "Core/NetPlayCommon.h"
- #include "Core/SyncIdentifier.h"
- #include "DiscIO/Enums.h"
- #include "DiscIO/RiivolutionPatcher.h"
- #include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
- #include "InputCommon/GCPadStatus.h"
- #include "InputCommon/InputConfig.h"
- #include "UICommon/GameFile.h"
- #if !defined(_WIN32)
- #include <sys/socket.h>
- #include <sys/types.h>
- #ifdef __HAIKU__
- #define _BSD_SOURCE
- #include <bsd/ifaddrs.h>
- #elif !defined ANDROID
- #include <ifaddrs.h>
- #endif
- #include <arpa/inet.h>
- #endif
- namespace NetPlay
- {
- NetPlayServer::~NetPlayServer()
- {
- if (is_connected)
- {
- m_do_loop = false;
- m_chunked_data_event.Set();
- m_chunked_data_complete_event.Set();
- if (m_chunked_data_thread.joinable())
- m_chunked_data_thread.join();
- m_thread.join();
- enet_host_destroy(m_server);
- if (Common::g_MainNetHost.get() == m_server)
- {
- Common::g_MainNetHost.release();
- }
- if (m_traversal_client)
- {
- Common::g_TraversalClient->m_Client = nullptr;
- Common::ReleaseTraversalClient();
- }
- }
- #ifdef USE_UPNP
- Common::UPnP::StopPortmapping();
- #endif
- }
- NetPlayServer::NetPlayServer(const u16 port, const bool forward_port, NetPlayUI* dialog,
- const NetTraversalConfig& traversal_config)
- : m_dialog(dialog)
- {
-
- if (enet_initialize() != 0)
- {
- PanicAlertFmtT("Enet Didn't Initialize");
- }
- m_pad_map.fill(0);
- m_gba_config.fill({});
- m_wiimote_map.fill(0);
- if (traversal_config.use_traversal)
- {
- if (!Common::EnsureTraversalClient(traversal_config.traversal_host,
- traversal_config.traversal_port,
- traversal_config.traversal_port_alt, port))
- {
- return;
- }
- Common::g_TraversalClient->m_Client = this;
- m_traversal_client = Common::g_TraversalClient.get();
- m_server = Common::g_MainNetHost.get();
- if (Common::g_TraversalClient->HasFailed())
- Common::g_TraversalClient->ReconnectToServer();
- }
- else
- {
- ENetAddress serverAddr;
- serverAddr.host = ENET_HOST_ANY;
- serverAddr.port = port;
- m_server = enet_host_create(&serverAddr, 10, CHANNEL_COUNT, 0, 0);
- if (m_server != nullptr)
- {
- m_server->mtu = std::min(m_server->mtu, NetPlay::MAX_ENET_MTU);
- m_server->intercept = Common::ENet::InterceptCallback;
- }
- SetupIndex();
- }
- if (m_server != nullptr)
- {
- is_connected = true;
- m_do_loop = true;
- m_thread = std::thread(&NetPlayServer::ThreadFunc, this);
- m_target_buffer_size = 5;
- m_chunked_data_thread = std::thread(&NetPlayServer::ChunkedDataThreadFunc, this);
- #ifdef USE_UPNP
- if (forward_port && !traversal_config.use_traversal)
- Common::UPnP::TryPortmapping(port);
- #endif
- }
- }
- static PlayerId* PeerPlayerId(ENetPeer* peer)
- {
- return static_cast<PlayerId*>(peer->data);
- }
- static void ClearPeerPlayerId(ENetPeer* peer)
- {
- if (peer->data)
- {
- delete PeerPlayerId(peer);
- peer->data = nullptr;
- }
- }
- void NetPlayServer::SetupIndex()
- {
- if (!Config::Get(Config::NETPLAY_USE_INDEX) || Config::Get(Config::NETPLAY_INDEX_NAME).empty() ||
- Config::Get(Config::NETPLAY_INDEX_REGION).empty())
- {
- return;
- }
- NetPlaySession session;
- session.name = Config::Get(Config::NETPLAY_INDEX_NAME);
- session.region = Config::Get(Config::NETPLAY_INDEX_REGION);
- session.has_password = !Config::Get(Config::NETPLAY_INDEX_PASSWORD).empty();
- session.method = m_traversal_client ? "traversal" : "direct";
- session.game_id = m_selected_game_name.empty() ? "UNKNOWN" : m_selected_game_name;
- session.player_count = static_cast<int>(m_players.size());
- session.in_game = m_is_running;
- session.port = GetPort();
- if (m_traversal_client)
- {
- if (!m_traversal_client->IsConnected())
- return;
- session.server_id = std::string(Common::g_TraversalClient->GetHostID().data(), 8);
- }
- else
- {
- Common::HttpRequest request;
-
- request.UseIPv4();
- Common::HttpRequest::Response response =
- request.Get("https://ip.dolphin-emu.org/", {{"X-Is-Dolphin", "1"}});
- if (!response.has_value())
- return;
- session.server_id = std::string(response->begin(), response->end());
- }
- session.EncryptID(Config::Get(Config::NETPLAY_INDEX_PASSWORD));
- bool success = m_index.Add(session);
- if (m_dialog != nullptr)
- m_dialog->OnIndexAdded(success, success ? "" : m_index.GetLastError());
- m_index.SetErrorCallback([this] {
- if (m_dialog != nullptr)
- m_dialog->OnIndexRefreshFailed(m_index.GetLastError());
- });
- }
- void NetPlayServer::ThreadFunc()
- {
- INFO_LOG_FMT(NETPLAY, "NetPlayServer starting.");
- while (m_do_loop)
- {
-
- if ((m_ping_timer.ElapsedMs() > 1000) || m_update_pings)
- {
-
- m_ping_key = static_cast<u32>(Common::Timer::NowMs());
- sf::Packet spac;
- spac << MessageID::Ping;
- spac << m_ping_key;
- m_ping_timer.Start();
- SendToClients(spac);
- m_index.SetPlayerCount(static_cast<int>(m_players.size()));
- m_index.SetGame(m_selected_game_name);
- m_index.SetInGame(m_is_running);
- m_update_pings = false;
- }
- ENetEvent netEvent;
- int net;
- if (m_traversal_client)
- m_traversal_client->HandleResends();
- net = enet_host_service(m_server, &netEvent, 1000);
- while (!m_async_queue.Empty())
- {
- INFO_LOG_FMT(NETPLAY, "Processing async queue event.");
- {
- std::lock_guard lkp(m_crit.players);
- INFO_LOG_FMT(NETPLAY, "Locked player mutex.");
- auto& e = m_async_queue.Front();
- if (e.target_mode == TargetMode::Only)
- {
- if (m_players.contains(e.target_pid))
- Send(m_players.at(e.target_pid).socket, e.packet, e.channel_id);
- }
- else
- {
- SendToClients(e.packet, e.target_pid, e.channel_id);
- }
- }
- INFO_LOG_FMT(NETPLAY, "Processing async queue event done.");
- m_async_queue.Pop();
- }
- if (net > 0)
- {
- switch (netEvent.type)
- {
- case ENET_EVENT_TYPE_CONNECT:
- {
-
-
- INFO_LOG_FMT(NETPLAY, "Peer connected from: {:x}:{}", netEvent.peer->address.host,
- netEvent.peer->address.port);
- }
- break;
- case ENET_EVENT_TYPE_RECEIVE:
- {
- INFO_LOG_FMT(NETPLAY, "enet_host_service: receive event");
- sf::Packet rpac;
- rpac.append(netEvent.packet->data, netEvent.packet->dataLength);
- if (!netEvent.peer->data)
- {
-
- ConnectionError error;
- {
- INFO_LOG_FMT(NETPLAY, "Initializing peer {:x}:{}", netEvent.peer->address.host,
- netEvent.peer->address.port);
- std::lock_guard lkg(m_crit.game);
- error = OnConnect(netEvent.peer, rpac);
- }
- if (error != ConnectionError::NoError)
- {
- INFO_LOG_FMT(NETPLAY, "Error {} initializing peer {:x}:{}", u8(error),
- netEvent.peer->address.host, netEvent.peer->address.port);
- sf::Packet spac;
- spac << error;
-
- Send(netEvent.peer, spac);
- ClearPeerPlayerId(netEvent.peer);
- enet_peer_disconnect_later(netEvent.peer, 0);
- }
- }
- else
- {
- auto it = m_players.find(*PeerPlayerId(netEvent.peer));
- Client& client = it->second;
- if (OnData(rpac, client) != 0)
- {
- INFO_LOG_FMT(NETPLAY, "Invalid packet from client {}, disconnecting.", client.pid);
-
- std::lock_guard lkg(m_crit.game);
- OnDisconnect(client);
- ClearPeerPlayerId(netEvent.peer);
- }
- else
- {
- INFO_LOG_FMT(NETPLAY, "successfully handled packet from client {}", client.pid);
- }
- }
- enet_packet_destroy(netEvent.packet);
- }
- break;
- case ENET_EVENT_TYPE_DISCONNECT:
- {
- INFO_LOG_FMT(NETPLAY, "enet_host_service: disconnect event");
- std::lock_guard lkg(m_crit.game);
- if (!netEvent.peer->data)
- {
- ERROR_LOG_FMT(NETPLAY, "enet_host_service: no peer data");
- break;
- }
- const auto player_id = *PeerPlayerId(netEvent.peer);
- auto it = m_players.find(player_id);
- if (it != m_players.end())
- {
- Client& client = it->second;
- INFO_LOG_FMT(NETPLAY, "Disconnecting client {}.", client.pid);
- OnDisconnect(client);
- ClearPeerPlayerId(netEvent.peer);
- }
- else
- {
- ERROR_LOG_FMT(NETPLAY, "Invalid player {} to disconnect.", player_id);
- }
- }
- break;
- default:
-
- if (static_cast<int>(netEvent.type) == Common::ENet::SKIPPABLE_EVENT)
- INFO_LOG_FMT(NETPLAY, "enet_host_service: skippable packet event");
- else
- ERROR_LOG_FMT(NETPLAY, "enet_host_service: unknown event type: {}", int(netEvent.type));
- break;
- }
- }
- else if (net == 0)
- {
- INFO_LOG_FMT(NETPLAY, "enet_host_service: no event occurred");
- }
- else
- {
- ERROR_LOG_FMT(NETPLAY, "enet_host_service error: {}", net);
- }
- }
- INFO_LOG_FMT(NETPLAY, "NetPlayServer shutting down.");
-
- for (auto& player_entry : m_players)
- {
- ClearPeerPlayerId(player_entry.second.socket);
- enet_peer_disconnect(player_entry.second.socket, 0);
- }
- m_players.clear();
- }
- static void SendSyncIdentifier(sf::Packet& spac, const SyncIdentifier& sync_identifier)
- {
-
- spac << static_cast<sf::Uint64>(sync_identifier.dol_elf_size);
- spac << sync_identifier.game_id;
- spac << sync_identifier.revision;
- spac << sync_identifier.disc_number;
- spac << sync_identifier.is_datel;
- for (const u8& x : sync_identifier.sync_hash)
- spac << x;
- }
- ConnectionError NetPlayServer::OnConnect(ENetPeer* incoming_connection, sf::Packet& received_packet)
- {
- std::string netplay_version;
- received_packet >> netplay_version;
- if (netplay_version != Common::GetScmRevGitStr())
- return ConnectionError::VersionMismatch;
- if (m_is_running || m_start_pending)
- return ConnectionError::GameRunning;
- if (m_players.size() >= 255)
- return ConnectionError::ServerFull;
- Client new_player{};
- new_player.pid = GiveFirstAvailableIDTo(incoming_connection);
- new_player.socket = incoming_connection;
- received_packet >> new_player.revision;
- received_packet >> new_player.name;
- if (StringUTF8CodePointCount(new_player.name) > MAX_NAME_LENGTH)
- return ConnectionError::NameTooLong;
-
-
- enet_peer_timeout(incoming_connection, 0, PEER_TIMEOUT.count(), PEER_TIMEOUT.count());
-
- m_update_pings = true;
- AssignNewUserAPad(new_player);
-
- SendResponseToAllPlayers(MessageID::PlayerJoin, new_player.pid, new_player.name,
- new_player.revision);
-
- SendResponseToPlayer(new_player, MessageID::ConnectionSuccessful, new_player.pid);
-
- if (!m_selected_game_name.empty())
- {
- sf::Packet send_packet;
- send_packet << MessageID::ChangeGame;
- SendSyncIdentifier(send_packet, m_selected_game_identifier);
- send_packet << m_selected_game_name;
- Send(new_player.socket, send_packet);
- }
- if (!m_host_input_authority)
- SendResponseToPlayer(new_player, MessageID::PadBuffer, m_target_buffer_size);
- SendResponseToPlayer(new_player, MessageID::HostInputAuthority, m_host_input_authority);
- for (const auto& existing_player : m_players)
- {
- SendResponseToPlayer(new_player, MessageID::PlayerJoin, existing_player.second.pid,
- existing_player.second.name, existing_player.second.revision);
- SendResponseToPlayer(new_player, MessageID::GameStatus, existing_player.second.pid,
- static_cast<u8>(existing_player.second.game_status));
- }
- if (Config::Get(Config::NETPLAY_ENABLE_QOS))
- new_player.qos_session = Common::QoSSession(new_player.socket);
- {
- std::lock_guard lkp(m_crit.players);
-
- m_players.emplace(*PeerPlayerId(new_player.socket), std::move(new_player));
-
- UpdatePadMapping();
- UpdateGBAConfig();
- UpdateWiimoteMapping();
- }
- return ConnectionError::NoError;
- }
- unsigned int NetPlayServer::OnDisconnect(const Client& player)
- {
- const PlayerId pid = player.pid;
- if (m_is_running)
- {
- for (PlayerId& mapping : m_pad_map)
- {
- if (mapping == pid && pid != 1)
- {
- std::lock_guard lkg(m_crit.game);
- m_is_running = false;
- sf::Packet spac;
- spac << MessageID::DisableGame;
-
- SendToClients(spac);
- break;
- }
- }
- }
- if (m_start_pending)
- {
- ChunkedDataAbort();
- m_dialog->OnGameStartAborted();
- m_start_pending = false;
- }
- sf::Packet spac;
- spac << MessageID::PlayerLeave;
- spac << pid;
- enet_peer_disconnect(player.socket, 0);
- std::lock_guard lkp(m_crit.players);
- auto it = m_players.find(player.pid);
- if (it != m_players.end())
- m_players.erase(it);
-
- SendToClients(spac);
- for (size_t i = 0; i < m_pad_map.size(); ++i)
- {
- if (m_pad_map[i] == pid)
- {
- m_pad_map[i] = 0;
- m_gba_config[i].enabled = false;
- UpdatePadMapping();
- UpdateGBAConfig();
- }
- }
- for (PlayerId& mapping : m_wiimote_map)
- {
- if (mapping == pid)
- {
- mapping = 0;
- UpdateWiimoteMapping();
- }
- }
- return 0;
- }
- PadMappingArray NetPlayServer::GetPadMapping() const
- {
- return m_pad_map;
- }
- GBAConfigArray NetPlayServer::GetGBAConfig() const
- {
- return m_gba_config;
- }
- PadMappingArray NetPlayServer::GetWiimoteMapping() const
- {
- return m_wiimote_map;
- }
- void NetPlayServer::SetPadMapping(const PadMappingArray& mappings)
- {
- m_pad_map = mappings;
- UpdatePadMapping();
- }
- 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();
- }
- void NetPlayServer::SetWiimoteMapping(const PadMappingArray& mappings)
- {
- m_wiimote_map = mappings;
- UpdateWiimoteMapping();
- }
- void NetPlayServer::UpdatePadMapping()
- {
- sf::Packet spac;
- spac << MessageID::PadMapping;
- for (PlayerId mapping : m_pad_map)
- {
- spac << mapping;
- }
- SendToClients(spac);
- }
- void NetPlayServer::UpdateGBAConfig()
- {
- sf::Packet spac;
- spac << MessageID::GBAConfig;
- for (const auto& config : m_gba_config)
- {
- spac << config.enabled << config.has_rom << config.title;
- for (auto& data : config.hash)
- spac << data;
- }
- SendToClients(spac);
- }
- void NetPlayServer::UpdateWiimoteMapping()
- {
- sf::Packet spac;
- spac << MessageID::WiimoteMapping;
- for (PlayerId mapping : m_wiimote_map)
- {
- spac << mapping;
- }
- SendToClients(spac);
- }
- void NetPlayServer::AdjustPadBufferSize(unsigned int size)
- {
- std::lock_guard lkg(m_crit.game);
- m_target_buffer_size = size;
-
- if (!m_host_input_authority)
- {
-
- sf::Packet spac;
- spac << MessageID::PadBuffer;
- spac << m_target_buffer_size;
- SendAsyncToClients(std::move(spac));
- }
- }
- void NetPlayServer::SetHostInputAuthority(const bool enable)
- {
- std::lock_guard lkg(m_crit.game);
- m_host_input_authority = enable;
-
- sf::Packet spac;
- spac << MessageID::HostInputAuthority;
- spac << m_host_input_authority;
- SendAsyncToClients(std::move(spac));
-
- if (!m_host_input_authority)
- AdjustPadBufferSize(m_target_buffer_size);
- }
- void NetPlayServer::SendAsync(sf::Packet&& packet, const PlayerId pid, const u8 channel_id)
- {
- {
- std::lock_guard lkq(m_crit.async_queue_write);
- m_async_queue.Push(AsyncQueueEntry{std::move(packet), pid, TargetMode::Only, channel_id});
- }
- Common::ENet::WakeupThread(m_server);
- }
- void NetPlayServer::SendAsyncToClients(sf::Packet&& packet, const PlayerId skip_pid,
- const u8 channel_id)
- {
- {
- std::lock_guard lkq(m_crit.async_queue_write);
- m_async_queue.Push(
- AsyncQueueEntry{std::move(packet), skip_pid, TargetMode::AllExcept, channel_id});
- }
- Common::ENet::WakeupThread(m_server);
- }
- void NetPlayServer::SendChunked(sf::Packet&& packet, const PlayerId pid, const std::string& title)
- {
- {
- std::lock_guard lkq(m_crit.chunked_data_queue_write);
- m_chunked_data_queue.Push(
- ChunkedDataQueueEntry{std::move(packet), pid, TargetMode::Only, title});
- }
- m_chunked_data_event.Set();
- }
- void NetPlayServer::SendChunkedToClients(sf::Packet&& packet, const PlayerId skip_pid,
- const std::string& title)
- {
- {
- std::lock_guard lkq(m_crit.chunked_data_queue_write);
- m_chunked_data_queue.Push(
- ChunkedDataQueueEntry{std::move(packet), skip_pid, TargetMode::AllExcept, title});
- }
- m_chunked_data_event.Set();
- }
- unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
- {
- MessageID mid;
- packet >> mid;
- INFO_LOG_FMT(NETPLAY, "Got client message: {:x} from client {}", static_cast<u8>(mid),
- player.pid);
-
-
- switch (mid)
- {
- case MessageID::ChatMessage:
- {
- std::string msg;
- packet >> msg;
-
- sf::Packet spac;
- spac << MessageID::ChatMessage;
- spac << player.pid;
- spac << msg;
- SendToClients(spac, player.pid);
- }
- break;
- case MessageID::ChunkedDataProgress:
- {
- u32 cid;
- packet >> cid;
- u64 progress = Common::PacketReadU64(packet);
- m_dialog->SetChunkedProgress(player.pid, progress);
- }
- break;
- case MessageID::ChunkedDataComplete:
- {
- u32 cid;
- packet >> cid;
- if (m_chunked_data_complete_count.contains(cid))
- {
- m_chunked_data_complete_count[cid]++;
- m_chunked_data_complete_event.Set();
- }
- }
- break;
- case MessageID::PadData:
- {
-
- if (player.current_game != m_current_game)
- break;
- sf::Packet spac;
- spac << (m_host_input_authority ? MessageID::PadHostData : MessageID::PadData);
- while (!packet.endOfPacket())
- {
- PadIndex map;
- packet >> map;
-
-
- if (m_pad_map.at(map) != player.pid)
- {
- return 1;
- }
- GCPadStatus pad;
- 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 << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX
- << pad.substickY << pad.triggerLeft << pad.triggerRight << pad.isConnected;
- }
- }
- if (m_host_input_authority)
- {
-
- if (m_current_golfer != 0 && m_players.contains(m_current_golfer))
- Send(m_players.at(m_current_golfer).socket, spac);
- }
- else
- {
- SendToClients(spac, player.pid);
- }
- }
- break;
- case MessageID::PadHostData:
- {
-
- if (m_current_golfer != 0 && player.pid != m_current_golfer)
- return 1;
- sf::Packet spac;
- spac << MessageID::PadData;
- while (!packet.endOfPacket())
- {
- PadIndex map;
- packet >> map;
- GCPadStatus pad;
- 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 << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX
- << pad.substickY << pad.triggerLeft << pad.triggerRight << pad.isConnected;
- }
- }
- SendToClients(spac, player.pid);
- }
- break;
- case MessageID::WiimoteData:
- {
-
- if (player.current_game != m_current_game)
- break;
- sf::Packet spac;
- spac << MessageID::WiimoteData;
- while (!packet.endOfPacket())
- {
- PadIndex map;
- packet >> map;
-
-
- if (m_wiimote_map.at(map) != player.pid)
- {
- return 1;
- }
- WiimoteEmu::SerializedWiimoteState pad;
- packet >> pad.length;
- if (pad.length > pad.data.size())
- return 1;
- for (size_t i = 0; i < pad.length; ++i)
- packet >> pad.data[i];
- spac << map;
- spac << pad.length;
- for (size_t i = 0; i < pad.length; ++i)
- spac << pad.data[i];
- }
- SendToClients(spac, player.pid);
- }
- break;
- case MessageID::GolfRequest:
- {
- PlayerId pid;
- packet >> pid;
-
- if (!m_players.contains(pid) || !PlayerHasControllerMapped(player.pid))
- break;
- if (m_host_input_authority && m_settings.golf_mode && m_pending_golfer == 0 &&
- m_current_golfer != pid && PlayerHasControllerMapped(pid))
- {
- m_pending_golfer = pid;
- sf::Packet spac;
- spac << MessageID::GolfPrepare;
- Send(m_players[pid].socket, spac);
- }
- }
- break;
- case MessageID::GolfRelease:
- {
- if (m_pending_golfer == 0)
- break;
- sf::Packet spac;
- spac << MessageID::GolfSwitch;
- spac << m_pending_golfer;
- SendToClients(spac);
- }
- break;
- case MessageID::GolfAcquire:
- {
- if (m_pending_golfer == 0)
- break;
- m_current_golfer = m_pending_golfer;
- m_pending_golfer = 0;
- }
- break;
- case MessageID::GolfPrepare:
- {
- if (m_pending_golfer == 0)
- break;
- m_current_golfer = 0;
- sf::Packet spac;
- spac << MessageID::GolfSwitch;
- spac << PlayerId{0};
- SendToClients(spac);
- }
- break;
- case MessageID::Pong:
- {
-
- const u32 ping = static_cast<u32>(m_ping_timer.ElapsedMs());
- u32 ping_key = 0;
- packet >> ping_key;
- if (m_ping_key == ping_key)
- {
- player.ping = ping;
- }
- sf::Packet spac;
- spac << MessageID::PlayerPingData;
- spac << player.pid;
- spac << player.ping;
- SendToClients(spac);
- }
- break;
- case MessageID::StartGame:
- {
- packet >> player.current_game;
- }
- break;
- case MessageID::StopGame:
- {
- if (!m_is_running)
- break;
- m_is_running = false;
-
- sf::Packet spac;
- spac << MessageID::StopGame;
- std::lock_guard lkp(m_crit.players);
- SendToClients(spac);
- }
- break;
- case MessageID::GameStatus:
- {
- SyncIdentifierComparison status;
- packet >> status;
- m_players[player.pid].game_status = status;
-
- sf::Packet spac;
- spac << MessageID::GameStatus;
- spac << player.pid;
- spac << status;
- SendToClients(spac);
- }
- break;
- case MessageID::ClientCapabilities:
- {
- packet >> m_players[player.pid].has_ipl_dump;
- packet >> m_players[player.pid].has_hardware_fma;
- }
- break;
- case MessageID::PowerButton:
- {
- sf::Packet spac;
- spac << MessageID::PowerButton;
- SendToClients(spac, player.pid);
- }
- break;
- case MessageID::TimeBase:
- {
- u64 timebase = Common::PacketReadU64(packet);
- u32 frame;
- packet >> frame;
- if (m_desync_detected)
- break;
- std::vector<std::pair<PlayerId, u64>>& timebases = m_timebase_by_frame[frame];
- timebases.emplace_back(player.pid, timebase);
- if (timebases.size() >= m_players.size())
- {
-
- if (!std::all_of(timebases.begin(), timebases.end(), [&](std::pair<PlayerId, u64> pair) {
- return pair.second == timebases[0].second;
- }))
- {
- int pid_to_blame = 0;
- for (auto pair : timebases)
- {
- if (std::all_of(timebases.begin(), timebases.end(), [&](std::pair<PlayerId, u64> other) {
- return other.first == pair.first || other.second != pair.second;
- }))
- {
-
- pid_to_blame = pair.first;
- break;
- }
- }
- sf::Packet spac;
- spac << MessageID::DesyncDetected;
- spac << pid_to_blame;
- spac << frame;
- SendToClients(spac);
- m_desync_detected = true;
- }
- m_timebase_by_frame.erase(frame);
- }
- }
- break;
- case MessageID::GameDigestProgress:
- {
- int progress;
- packet >> progress;
- sf::Packet spac;
- spac << MessageID::GameDigestProgress;
- spac << player.pid;
- spac << progress;
- SendToClients(spac);
- }
- break;
- case MessageID::GameDigestResult:
- {
- std::string result;
- packet >> result;
- sf::Packet spac;
- spac << MessageID::GameDigestResult;
- spac << player.pid;
- spac << result;
- SendToClients(spac);
- }
- break;
- case MessageID::GameDigestError:
- {
- std::string error;
- packet >> error;
- sf::Packet spac;
- spac << MessageID::GameDigestError;
- spac << player.pid;
- spac << error;
- SendToClients(spac);
- }
- break;
- case MessageID::SyncSaveData:
- {
- SyncSaveDataID sub_id;
- packet >> sub_id;
- INFO_LOG_FMT(NETPLAY, "Got client SyncSaveData message: {:x} from client {}", u8(sub_id),
- player.pid);
- switch (sub_id)
- {
- case SyncSaveDataID::Success:
- {
- if (m_start_pending)
- {
- m_save_data_synced_players++;
- if (m_save_data_synced_players >= m_players.size() - 1)
- {
- INFO_LOG_FMT(NETPLAY, "SyncSaveData: All players synchronized. ({} >= {})",
- m_save_data_synced_players, m_players.size() - 1);
- m_dialog->AppendChat(Common::GetStringT("All players' saves synchronized."));
-
- m_saves_synced = true;
- CheckSyncAndStartGame();
- }
- else
- {
- INFO_LOG_FMT(NETPLAY, "SyncSaveData: Not all players synchronized. ({} < {})",
- m_save_data_synced_players, m_players.size() - 1);
- }
- }
- else
- {
- INFO_LOG_FMT(NETPLAY, "SyncSaveData: Start not pending.");
- }
- }
- break;
- case SyncSaveDataID::Failure:
- {
- m_dialog->AppendChat(Common::FmtFormatT("{0} failed to synchronize.", player.name));
- m_dialog->OnGameStartAborted();
- ChunkedDataAbort();
- m_start_pending = false;
- }
- break;
- default:
- PanicAlertFmtT(
- "Unknown SYNC_SAVE_DATA message with id:{0} received from player:{1} Kicking player!",
- static_cast<u8>(sub_id), player.pid);
- return 1;
- }
- }
- break;
- case MessageID::SyncCodes:
- {
-
- SyncCodeID sub_id;
- packet >> sub_id;
- INFO_LOG_FMT(NETPLAY, "Got client SyncCodes message: {:x} from client {}", u8(sub_id),
- player.pid);
-
- switch (sub_id)
- {
- case SyncCodeID::Success:
- {
- if (m_start_pending)
- {
- if (++m_codes_synced_players >= m_players.size() - 1)
- {
- INFO_LOG_FMT(NETPLAY, "SyncCodes: All players synchronized. ({} >= {})",
- m_codes_synced_players, m_players.size() - 1);
- m_dialog->AppendChat(Common::GetStringT("All players' codes synchronized."));
-
- m_codes_synced = true;
- CheckSyncAndStartGame();
- }
- else
- {
- INFO_LOG_FMT(NETPLAY, "SyncCodes: Not all players synchronized. ({} < {})",
- m_codes_synced_players, m_players.size() - 1);
- }
- }
- else
- {
- INFO_LOG_FMT(NETPLAY, "SyncCodes: Start not pending.");
- }
- }
- break;
- case SyncCodeID::Failure:
- {
- m_dialog->AppendChat(Common::FmtFormatT("{0} failed to synchronize codes.", player.name));
- m_dialog->OnGameStartAborted();
- m_start_pending = false;
- }
- break;
- default:
- PanicAlertFmtT(
- "Unknown SYNC_GECKO_CODES message with id:{0} received from player:{1} Kicking player!",
- static_cast<u8>(sub_id), player.pid);
- return 1;
- }
- }
- break;
- default:
- PanicAlertFmtT("Unknown message with id:{0} received from player:{1} Kicking player!",
- static_cast<u8>(mid), player.pid);
-
- return 1;
- }
- return 0;
- }
- void NetPlayServer::OnTraversalStateChanged()
- {
- const Common::TraversalClient::State state = m_traversal_client->GetState();
- if (Common::g_TraversalClient->GetHostID()[0] != '\0')
- SetupIndex();
- if (!m_dialog)
- return;
- if (state == Common::TraversalClient::State::Failure)
- m_dialog->OnTraversalError(m_traversal_client->GetFailureReason());
- m_dialog->OnTraversalStateChanged(state);
- }
- void NetPlayServer::OnTtlDetermined(u8 ttl)
- {
- m_dialog->OnTtlDetermined(ttl);
- }
- void NetPlayServer::SendChatMessage(const std::string& msg)
- {
- sf::Packet spac;
- spac << MessageID::ChatMessage;
- spac << PlayerId{0};
- spac << msg;
- SendAsyncToClients(std::move(spac));
- }
- bool NetPlayServer::ChangeGame(const SyncIdentifier& sync_identifier,
- const std::string& netplay_name)
- {
- std::lock_guard lkg(m_crit.game);
- INFO_LOG_FMT(NETPLAY, "Changing game to {} ({:02x}).", netplay_name,
- fmt::join(sync_identifier.sync_hash, ""));
- m_selected_game_identifier = sync_identifier;
- m_selected_game_name = netplay_name;
-
- sf::Packet spac;
- spac << MessageID::ChangeGame;
- SendSyncIdentifier(spac, m_selected_game_identifier);
- spac << m_selected_game_name;
- SendAsyncToClients(std::move(spac));
- return true;
- }
- bool NetPlayServer::ComputeGameDigest(const SyncIdentifier& sync_identifier)
- {
- sf::Packet spac;
- spac << MessageID::ComputeGameDigest;
- SendSyncIdentifier(spac, sync_identifier);
- SendAsyncToClients(std::move(spac));
- return true;
- }
- bool NetPlayServer::AbortGameDigest()
- {
- sf::Packet spac;
- spac << MessageID::GameDigestAbort;
- SendAsyncToClients(std::move(spac));
- return true;
- }
- bool NetPlayServer::SetupNetSettings()
- {
- const auto game = m_dialog->FindGameFile(m_selected_game_identifier);
- if (game == nullptr)
- {
- ERROR_LOG_FMT(NETPLAY, "Game {:02x} not found in game list.",
- fmt::join(m_selected_game_identifier.sync_hash, ""));
- PanicAlertFmtT("Selected game doesn't exist in game list!");
- return false;
- }
- INFO_LOG_FMT(NETPLAY, "Loading game settings for {:02x}.",
- fmt::join(m_selected_game_identifier.sync_hash, ""));
- NetPlay::NetSettings settings;
-
- Config::AddLayer(
- ConfigLoaders::GenerateGlobalGameConfigLoader(game->GetGameID(), game->GetRevision()));
- Config::AddLayer(
- ConfigLoaders::GenerateLocalGameConfigLoader(game->GetGameID(), game->GetRevision()));
-
- settings.cpu_thread = Config::Get(Config::MAIN_CPU_THREAD);
- settings.cpu_core = Config::Get(Config::MAIN_CPU_CORE);
- settings.enable_cheats = Config::AreCheatsEnabled();
- settings.selected_language = Config::Get(Config::MAIN_GC_LANGUAGE);
- settings.override_region_settings = Config::Get(Config::MAIN_OVERRIDE_REGION_SETTINGS);
- settings.dsp_hle = Config::Get(Config::MAIN_DSP_HLE);
- settings.dsp_enable_jit = Config::Get(Config::MAIN_DSP_JIT);
- settings.ram_override_enable = Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE);
- settings.mem1_size = Config::Get(Config::MAIN_MEM1_SIZE);
- settings.mem2_size = Config::Get(Config::MAIN_MEM2_SIZE);
- settings.fallback_region = Config::Get(Config::MAIN_FALLBACK_REGION);
- settings.allow_sd_writes = Config::Get(Config::MAIN_ALLOW_SD_WRITES);
- settings.oc_enable = Config::Get(Config::MAIN_OVERCLOCK_ENABLE);
- settings.oc_factor = Config::Get(Config::MAIN_OVERCLOCK);
- for (ExpansionInterface::Slot slot : ExpansionInterface::SLOTS)
- {
- ExpansionInterface::EXIDeviceType device;
- if (slot == ExpansionInterface::Slot::SP1)
- {
-
- device = ExpansionInterface::EXIDeviceType::None;
- }
- else
- {
- device = Config::Get(Config::GetInfoForEXIDevice(slot));
- }
- settings.exi_device[slot] = device;
- }
- settings.memcard_size_override = Config::Get(Config::MAIN_MEMORY_CARD_SIZE);
- for (size_t i = 0; i < Config::SYSCONF_SETTINGS.size(); ++i)
- {
- std::visit(
- [&](auto* info) {
- static_assert(sizeof(info->GetDefaultValue()) <= sizeof(u32));
- settings.sysconf_settings[i] = static_cast<u32>(Config::Get(*info));
- },
- Config::SYSCONF_SETTINGS[i].config_info);
- }
- settings.efb_access_enable = Config::Get(Config::GFX_HACK_EFB_ACCESS_ENABLE);
- settings.bbox_enable = Config::Get(Config::GFX_HACK_BBOX_ENABLE);
- settings.force_progressive = Config::Get(Config::GFX_HACK_FORCE_PROGRESSIVE);
- settings.efb_to_texture_enable = Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM);
- settings.xfb_to_texture_enable = Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM);
- settings.disable_copy_to_vram = Config::Get(Config::GFX_HACK_DISABLE_COPY_TO_VRAM);
- settings.immediate_xfb_enable = Config::Get(Config::GFX_HACK_IMMEDIATE_XFB);
- settings.efb_emulate_format_changes = Config::Get(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES);
- settings.safe_texture_cache_color_samples =
- Config::Get(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES);
- settings.perf_queries_enable = Config::Get(Config::GFX_PERF_QUERIES_ENABLE);
- settings.float_exceptions = Config::Get(Config::MAIN_FLOAT_EXCEPTIONS);
- settings.divide_by_zero_exceptions = Config::Get(Config::MAIN_DIVIDE_BY_ZERO_EXCEPTIONS);
- settings.fprf = Config::Get(Config::MAIN_FPRF);
- settings.accurate_nans = Config::Get(Config::MAIN_ACCURATE_NANS);
- settings.disable_icache = Config::Get(Config::MAIN_DISABLE_ICACHE);
- settings.sync_on_skip_idle = Config::Get(Config::MAIN_SYNC_ON_SKIP_IDLE);
- settings.sync_gpu = Config::Get(Config::MAIN_SYNC_GPU);
- settings.sync_gpu_max_distance = Config::Get(Config::MAIN_SYNC_GPU_MAX_DISTANCE);
- settings.sync_gpu_min_distance = Config::Get(Config::MAIN_SYNC_GPU_MIN_DISTANCE);
- settings.sync_gpu_overclock = Config::Get(Config::MAIN_SYNC_GPU_OVERCLOCK);
- settings.jit_follow_branch = Config::Get(Config::MAIN_JIT_FOLLOW_BRANCH);
- settings.fast_disc_speed = Config::Get(Config::MAIN_FAST_DISC_SPEED);
- settings.mmu = Config::Get(Config::MAIN_MMU);
- settings.fastmem = Config::Get(Config::MAIN_FASTMEM);
- settings.skip_ipl = Config::Get(Config::MAIN_SKIP_IPL) || !DoAllPlayersHaveIPLDump();
- settings.load_ipl_dump = Config::Get(Config::SESSION_LOAD_IPL_DUMP) && DoAllPlayersHaveIPLDump();
- settings.vertex_rounding = Config::Get(Config::GFX_HACK_VERTEX_ROUNDING);
- settings.internal_resolution = Config::Get(Config::GFX_EFB_SCALE);
- settings.efb_scaled_copy = Config::Get(Config::GFX_HACK_COPY_EFB_SCALED);
- settings.fast_depth_calc = Config::Get(Config::GFX_FAST_DEPTH_CALC);
- settings.enable_pixel_lighting = Config::Get(Config::GFX_ENABLE_PIXEL_LIGHTING);
- settings.widescreen_hack = Config::Get(Config::GFX_WIDESCREEN_HACK);
- settings.force_texture_filtering = Config::Get(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING);
- settings.max_anisotropy = Config::Get(Config::GFX_ENHANCE_MAX_ANISOTROPY);
- settings.force_true_color = Config::Get(Config::GFX_ENHANCE_FORCE_TRUE_COLOR);
- settings.disable_copy_filter = Config::Get(Config::GFX_ENHANCE_DISABLE_COPY_FILTER);
- settings.disable_fog = Config::Get(Config::GFX_DISABLE_FOG);
- settings.arbitrary_mipmap_detection = Config::Get(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION);
- settings.arbitrary_mipmap_detection_threshold =
- Config::Get(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION_THRESHOLD);
- settings.enable_gpu_texture_decoding = Config::Get(Config::GFX_ENABLE_GPU_TEXTURE_DECODING);
- settings.defer_efb_copies = Config::Get(Config::GFX_HACK_DEFER_EFB_COPIES);
- settings.efb_access_tile_size = Config::Get(Config::GFX_HACK_EFB_ACCESS_TILE_SIZE);
- settings.efb_access_defer_invalidation = Config::Get(Config::GFX_HACK_EFB_DEFER_INVALIDATION);
- settings.savedata_load = Config::Get(Config::NETPLAY_SAVEDATA_LOAD);
- settings.savedata_write = settings.savedata_load && Config::Get(Config::NETPLAY_SAVEDATA_WRITE);
- settings.savedata_sync_all_wii =
- settings.savedata_load && Config::Get(Config::NETPLAY_SAVEDATA_SYNC_ALL_WII);
- settings.strict_settings_sync = Config::Get(Config::NETPLAY_STRICT_SETTINGS_SYNC);
- settings.sync_codes = Config::Get(Config::NETPLAY_SYNC_CODES);
- settings.golf_mode = Config::Get(Config::NETPLAY_NETWORK_MODE) == "golf";
- settings.use_fma = DoAllPlayersHaveHardwareFMA();
- settings.hide_remote_gbas = Config::Get(Config::NETPLAY_HIDE_REMOTE_GBAS);
-
- Config::RemoveLayer(Config::LayerType::GlobalGame);
- Config::RemoveLayer(Config::LayerType::LocalGame);
- m_settings = settings;
- return true;
- }
- bool NetPlayServer::DoAllPlayersHaveIPLDump() const
- {
- return std::all_of(m_players.begin(), m_players.end(),
- [](const auto& p) { return p.second.has_ipl_dump; });
- }
- bool NetPlayServer::DoAllPlayersHaveHardwareFMA() const
- {
- return std::all_of(m_players.begin(), m_players.end(),
- [](const auto& p) { return p.second.has_hardware_fma; });
- }
- struct SaveSyncInfo
- {
- u8 save_count = 0;
- std::shared_ptr<const UICommon::GameFile> game;
- bool has_wii_save = false;
- std::unique_ptr<IOS::HLE::FS::FileSystem> configured_fs;
- std::optional<std::vector<u8>> mii_data;
- std::vector<std::pair<u64, WiiSave::StoragePointer>> wii_saves;
- std::optional<DiscIO::Riivolution::SavegameRedirect> redirected_save;
- };
- bool NetPlayServer::RequestStartGame()
- {
- INFO_LOG_FMT(NETPLAY, "Start Game requested.");
- if (!SetupNetSettings())
- return false;
- bool start_now = true;
- if (m_settings.savedata_load)
- {
- auto save_sync_info = CollectSaveSyncInfo();
- if (!save_sync_info)
- {
- PanicAlertFmtT("Error collecting save data!");
- m_start_pending = false;
- return false;
- }
- if (save_sync_info->has_wii_save)
- {
-
- std::vector<u64> titles;
- for (const auto& [title_id, storage] : save_sync_info->wii_saves)
- titles.push_back(title_id);
- m_dialog->SetHostWiiSyncData(
- std::move(titles),
- save_sync_info->redirected_save ? save_sync_info->redirected_save->m_target_path : "");
- }
- if (m_players.size() > 1)
- {
- start_now = false;
- m_start_pending = true;
- if (!SyncSaveData(*save_sync_info))
- {
- PanicAlertFmtT("Error synchronizing save data!");
- m_start_pending = false;
- return false;
- }
- }
- }
-
- if (m_settings.sync_codes && m_players.size() > 1)
- {
- start_now = false;
- m_start_pending = true;
- if (!SyncCodes())
- {
- PanicAlertFmtT("Error synchronizing cheat codes!");
- m_start_pending = false;
- return false;
- }
- }
- if (start_now)
- {
- return StartGame();
- }
- INFO_LOG_FMT(NETPLAY, "Waiting for data sync with clients.");
- return true;
- }
- bool NetPlayServer::StartGame()
- {
- INFO_LOG_FMT(NETPLAY, "Starting game.");
- m_timebase_by_frame.clear();
- m_desync_detected = false;
- std::lock_guard lkg(m_crit.game);
-
- m_current_game = static_cast<u32>(Common::Timer::NowMs());
-
- if (!m_host_input_authority)
- AdjustPadBufferSize(m_target_buffer_size);
- m_current_golfer = 1;
- m_pending_golfer = 0;
- const sf::Uint64 initial_rtc = GetInitialNetPlayRTC();
- const std::string region = Config::GetDirectoryForRegion(
- Config::ToGameCubeRegion(m_dialog->FindGameFile(m_selected_game_identifier)->GetRegion()));
-
- SConfig::GetInstance().m_strSRAM = File::GetUserPath(F_GCSRAM_IDX);
- InitSRAM(&m_settings.sram, SConfig::GetInstance().m_strSRAM);
-
- sf::Packet spac;
- spac << MessageID::StartGame;
- spac << m_current_game;
- spac << m_settings.cpu_thread;
- spac << m_settings.cpu_core;
- spac << m_settings.enable_cheats;
- spac << m_settings.selected_language;
- spac << m_settings.override_region_settings;
- spac << m_settings.dsp_enable_jit;
- spac << m_settings.dsp_hle;
- spac << m_settings.ram_override_enable;
- spac << m_settings.mem1_size;
- spac << m_settings.mem2_size;
- spac << m_settings.fallback_region;
- spac << m_settings.allow_sd_writes;
- spac << m_settings.oc_enable;
- spac << m_settings.oc_factor;
- for (auto slot : ExpansionInterface::SLOTS)
- spac << static_cast<int>(m_settings.exi_device[slot]);
- spac << m_settings.memcard_size_override;
- for (u32 value : m_settings.sysconf_settings)
- spac << value;
- spac << m_settings.efb_access_enable;
- spac << m_settings.bbox_enable;
- spac << m_settings.force_progressive;
- spac << m_settings.efb_to_texture_enable;
- spac << m_settings.xfb_to_texture_enable;
- spac << m_settings.disable_copy_to_vram;
- spac << m_settings.immediate_xfb_enable;
- spac << m_settings.efb_emulate_format_changes;
- spac << m_settings.safe_texture_cache_color_samples;
- spac << m_settings.perf_queries_enable;
- spac << m_settings.float_exceptions;
- spac << m_settings.divide_by_zero_exceptions;
- spac << m_settings.fprf;
- spac << m_settings.accurate_nans;
- spac << m_settings.disable_icache;
- spac << m_settings.sync_on_skip_idle;
- spac << m_settings.sync_gpu;
- spac << m_settings.sync_gpu_max_distance;
- spac << m_settings.sync_gpu_min_distance;
- spac << m_settings.sync_gpu_overclock;
- spac << m_settings.jit_follow_branch;
- spac << m_settings.fast_disc_speed;
- spac << m_settings.mmu;
- spac << m_settings.fastmem;
- spac << m_settings.skip_ipl;
- spac << m_settings.load_ipl_dump;
- spac << m_settings.vertex_rounding;
- spac << m_settings.internal_resolution;
- spac << m_settings.efb_scaled_copy;
- spac << m_settings.fast_depth_calc;
- spac << m_settings.enable_pixel_lighting;
- spac << m_settings.widescreen_hack;
- spac << m_settings.force_texture_filtering;
- spac << m_settings.max_anisotropy;
- spac << m_settings.force_true_color;
- spac << m_settings.disable_copy_filter;
- spac << m_settings.disable_fog;
- spac << m_settings.arbitrary_mipmap_detection;
- spac << m_settings.arbitrary_mipmap_detection_threshold;
- spac << m_settings.enable_gpu_texture_decoding;
- spac << m_settings.defer_efb_copies;
- spac << m_settings.efb_access_tile_size;
- spac << m_settings.efb_access_defer_invalidation;
- spac << m_settings.savedata_load;
- spac << m_settings.savedata_write;
- spac << m_settings.savedata_sync_all_wii;
- spac << m_settings.strict_settings_sync;
- spac << initial_rtc;
- spac << region;
- spac << m_settings.sync_codes;
- spac << m_settings.golf_mode;
- spac << m_settings.use_fma;
- spac << m_settings.hide_remote_gbas;
- for (size_t i = 0; i < sizeof(m_settings.sram); ++i)
- spac << m_settings.sram[i];
- SendAsyncToClients(std::move(spac));
- m_start_pending = false;
- m_is_running = true;
- return true;
- }
- void NetPlayServer::AbortGameStart()
- {
- if (m_start_pending)
- {
- INFO_LOG_FMT(NETPLAY, "Aborting game start.");
- m_dialog->OnGameStartAborted();
- ChunkedDataAbort();
- m_start_pending = false;
- }
- else
- {
- INFO_LOG_FMT(NETPLAY, "Aborting game start but no game start pending.");
- }
- }
- std::optional<SaveSyncInfo> NetPlayServer::CollectSaveSyncInfo()
- {
- INFO_LOG_FMT(NETPLAY, "Collecting saves.");
- SaveSyncInfo sync_info;
- sync_info.save_count = 0;
- for (ExpansionInterface::Slot slot : ExpansionInterface::MEMCARD_SLOTS)
- {
- if (m_settings.exi_device[slot] == ExpansionInterface::EXIDeviceType::MemoryCard)
- {
- INFO_LOG_FMT(NETPLAY, "Adding memory card (raw) in slot {}.", slot);
- ++sync_info.save_count;
- }
- else if (Config::Get(Config::GetInfoForEXIDevice(slot)) ==
- ExpansionInterface::EXIDeviceType::MemoryCardFolder)
- {
- INFO_LOG_FMT(NETPLAY, "Adding memory card (folder) in slot {}.", slot);
- ++sync_info.save_count;
- }
- }
- sync_info.game = m_dialog->FindGameFile(m_selected_game_identifier);
- if (sync_info.game == nullptr)
- {
- PanicAlertFmtT("Selected game doesn't exist in game list!");
- return std::nullopt;
- }
- sync_info.has_wii_save = false;
- if (m_settings.savedata_load && (sync_info.game->GetPlatform() == DiscIO::Platform::WiiDisc ||
- sync_info.game->GetPlatform() == DiscIO::Platform::WiiWAD ||
- sync_info.game->GetPlatform() == DiscIO::Platform::ELFOrDOL))
- {
- INFO_LOG_FMT(NETPLAY, "Adding Wii saves.");
- sync_info.has_wii_save = true;
- ++sync_info.save_count;
- sync_info.configured_fs = IOS::HLE::FS::MakeFileSystem(IOS::HLE::FS::Location::Configured);
- if (m_settings.savedata_sync_all_wii)
- {
- IOS::HLE::Kernel ios;
- for (const u64 title : ios.GetESCore().GetInstalledTitles())
- {
- auto save = WiiSave::MakeNandStorage(sync_info.configured_fs.get(), title);
- if (save && save->ReadHeader().has_value() && save->ReadBkHeader().has_value() &&
- save->ReadFiles().has_value())
- {
- sync_info.wii_saves.emplace_back(title, std::move(save));
- }
- else
- {
- INFO_LOG_FMT(NETPLAY, "Skipping Wii save of title {:016x}.", title);
- }
- }
- }
- else if (sync_info.game->GetPlatform() == DiscIO::Platform::WiiDisc ||
- sync_info.game->GetPlatform() == DiscIO::Platform::WiiWAD)
- {
- auto save =
- WiiSave::MakeNandStorage(sync_info.configured_fs.get(), sync_info.game->GetTitleID());
- sync_info.wii_saves.emplace_back(sync_info.game->GetTitleID(), std::move(save));
- }
- {
- auto file = sync_info.configured_fs->OpenFile(
- IOS::PID_KERNEL, IOS::PID_KERNEL, Common::GetMiiDatabasePath(), IOS::HLE::FS::Mode::Read);
- if (file)
- {
- std::vector<u8> file_data(file->GetStatus()->size);
- if (!file->Read(file_data.data(), file_data.size()))
- return std::nullopt;
- sync_info.mii_data = std::move(file_data);
- }
- }
- if (sync_info.game->GetBlobType() == DiscIO::BlobType::MOD_DESCRIPTOR)
- {
- auto boot_params = BootParameters::GenerateFromFile(sync_info.game->GetFilePath());
- if (boot_params)
- {
- sync_info.redirected_save =
- DiscIO::Riivolution::ExtractSavegameRedirect(boot_params->riivolution_patches);
- }
- }
- }
- for (size_t i = 0; i < m_gba_config.size(); ++i)
- {
- const auto& config = m_gba_config[i];
- if (config.enabled && config.has_rom)
- {
- INFO_LOG_FMT(NETPLAY, "Adding GBA save in slot {}.", i);
- ++sync_info.save_count;
- }
- }
- return sync_info;
- }
- bool NetPlayServer::SyncSaveData(const SaveSyncInfo& sync_info)
- {
- INFO_LOG_FMT(NETPLAY, "Sending {} savegame chunks to clients.", sync_info.save_count);
-
- m_saves_synced = false;
- m_save_data_synced_players = 0;
- {
- sf::Packet pac;
- pac << MessageID::SyncSaveData;
- pac << SyncSaveDataID::Notify;
- pac << sync_info.save_count;
-
- SendAsyncToClients(std::move(pac), 0, CHUNKED_DATA_CHANNEL);
- }
- if (sync_info.save_count == 0)
- return true;
- const auto game_region = sync_info.game->GetRegion();
- const auto gamecube_region = Config::ToGameCubeRegion(game_region);
- const std::string region = Config::GetDirectoryForRegion(gamecube_region);
- for (ExpansionInterface::Slot slot : ExpansionInterface::MEMCARD_SLOTS)
- {
- const bool is_slot_a = slot == ExpansionInterface::Slot::A;
- if (m_settings.exi_device[slot] == ExpansionInterface::EXIDeviceType::MemoryCard)
- {
- const int size_override = m_settings.memcard_size_override;
- const u16 card_size_mbits =
- size_override >= 0 && size_override <= 4 ?
- static_cast<u16>(Memcard::MBIT_SIZE_MEMORY_CARD_59 << size_override) :
- Memcard::MBIT_SIZE_MEMORY_CARD_2043;
- const std::string path = Config::GetMemcardPath(slot, game_region, card_size_mbits);
- sf::Packet pac;
- pac << MessageID::SyncSaveData;
- pac << SyncSaveDataID::RawData;
- pac << is_slot_a << region << size_override;
- if (File::Exists(path))
- {
- INFO_LOG_FMT(NETPLAY, "Sending data of raw memcard {} in slot {}.", path,
- is_slot_a ? 'A' : 'B');
- if (!CompressFileIntoPacket(path, pac))
- return false;
- }
- else
- {
-
- INFO_LOG_FMT(NETPLAY, "Sending empty marker for raw memcard {} in slot {}.", path,
- is_slot_a ? 'A' : 'B');
- pac << sf::Uint64{0};
- }
- SendChunkedToClients(std::move(pac), 1,
- fmt::format("Memory Card {} Synchronization", is_slot_a ? 'A' : 'B'));
- }
- else if (Config::Get(Config::GetInfoForEXIDevice(slot)) ==
- ExpansionInterface::EXIDeviceType::MemoryCardFolder)
- {
- const std::string path = Config::GetGCIFolderPath(slot, gamecube_region);
- sf::Packet pac;
- pac << MessageID::SyncSaveData;
- pac << SyncSaveDataID::GCIData;
- pac << is_slot_a;
- if (File::IsDirectory(path))
- {
- std::vector<std::string> files =
- GCMemcardDirectory::GetFileNamesForGameID(path + DIR_SEP, sync_info.game->GetGameID());
- INFO_LOG_FMT(NETPLAY, "Sending data of GCI memcard {} in slot {} ({} files).", path,
- is_slot_a ? 'A' : 'B', files.size());
- pac << static_cast<u8>(files.size());
- for (const std::string& file : files)
- {
- const std::string filename = file.substr(file.find_last_of('/') + 1);
- INFO_LOG_FMT(NETPLAY, "Sending GCI {}.", filename);
- pac << filename;
- if (!CompressFileIntoPacket(file, pac))
- return false;
- }
- }
- else
- {
- INFO_LOG_FMT(NETPLAY, "Sending empty marker for GCI memcard {} in slot {}.", path,
- is_slot_a ? 'A' : 'B');
- pac << static_cast<u8>(0);
- }
- SendChunkedToClients(std::move(pac), 1,
- fmt::format("GCI Folder {} Synchronization", is_slot_a ? 'A' : 'B'));
- }
- }
- if (sync_info.has_wii_save)
- {
- sf::Packet pac;
- pac << MessageID::SyncSaveData;
- pac << SyncSaveDataID::WiiData;
-
- if (sync_info.mii_data)
- {
- INFO_LOG_FMT(NETPLAY, "Sending Mii data.");
- pac << true;
- if (!CompressBufferIntoPacket(*sync_info.mii_data, pac))
- return false;
- }
- else
- {
- INFO_LOG_FMT(NETPLAY, "Not sending Mii data.");
- pac << false;
- }
-
- INFO_LOG_FMT(NETPLAY, "Sending {} Wii saves.", sync_info.wii_saves.size());
- pac << static_cast<u32>(sync_info.wii_saves.size());
- for (const auto& [title_id, storage] : sync_info.wii_saves)
- {
- pac << sf::Uint64{title_id};
- if (storage->SaveExists())
- {
- const std::optional<WiiSave::Header> header = storage->ReadHeader();
- const std::optional<WiiSave::BkHeader> bk_header = storage->ReadBkHeader();
- const std::optional<std::vector<WiiSave::Storage::SaveFile>> files = storage->ReadFiles();
- if (!header || !bk_header || !files)
- {
- INFO_LOG_FMT(NETPLAY, "Wii save of title {:016x} is corrupted.", title_id);
- return false;
- }
- INFO_LOG_FMT(NETPLAY, "Sending Wii save of title {:016x}.", title_id);
- pac << true;
-
- pac << sf::Uint64{header->tid};
- pac << header->banner_size << header->permissions << header->unk1;
- for (u8 byte : header->md5)
- pac << byte;
- pac << header->unk2;
- for (size_t i = 0; i < header->banner_size; i++)
- pac << header->banner[i];
-
- pac << bk_header->size << bk_header->magic << bk_header->ngid << bk_header->number_of_files
- << bk_header->size_of_files << bk_header->unk1 << bk_header->unk2
- << bk_header->total_size;
- for (u8 byte : bk_header->unk3)
- pac << byte;
- pac << sf::Uint64{bk_header->tid};
- for (u8 byte : bk_header->mac_address)
- pac << byte;
-
- for (const WiiSave::Storage::SaveFile& file : *files)
- {
- INFO_LOG_FMT(NETPLAY, "Sending Wii save data of type {} at {}",
- static_cast<u8>(file.type), file.path);
- pac << file.mode << file.attributes << file.type << file.path;
- if (file.type == WiiSave::Storage::SaveFile::Type::File)
- {
- const std::optional<std::vector<u8>>& data = *file.data;
- if (!data || !CompressBufferIntoPacket(*data, pac))
- return false;
- }
- }
- }
- else
- {
- INFO_LOG_FMT(NETPLAY, "No data for Wii save of title {:016x}.", title_id);
- pac << false;
- }
- }
- if (sync_info.redirected_save)
- {
- INFO_LOG_FMT(NETPLAY, "Sending redirected save at {}.",
- sync_info.redirected_save->m_target_path);
- pac << true;
- if (!CompressFolderIntoPacket(sync_info.redirected_save->m_target_path, pac))
- return false;
- }
- else
- {
- INFO_LOG_FMT(NETPLAY, "Not sending redirected save.");
- pac << false;
- }
- 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 << MessageID::SyncSaveData;
- pac << SyncSaveDataID::GBAData;
- 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))
- {
- INFO_LOG_FMT(NETPLAY, "Sending data of GBA save at {} for slot {}.", path, i);
- if (!CompressFileIntoPacket(path, pac))
- return false;
- }
- else
- {
-
- INFO_LOG_FMT(NETPLAY, "Sending empty marker for GBA save at {} for slot {}.", path, i);
- pac << sf::Uint64{0};
- }
- SendChunkedToClients(std::move(pac), 1,
- fmt::format("GBA{} Save File Synchronization", i + 1));
- }
- }
- return true;
- }
- bool NetPlayServer::SyncCodes()
- {
- INFO_LOG_FMT(NETPLAY, "Sending codes to clients.");
-
- m_codes_synced = false;
-
- const auto game = m_dialog->FindGameFile(m_selected_game_identifier);
- if (game == nullptr)
- {
- PanicAlertFmtT("Selected game doesn't exist in game list!");
- return false;
- }
-
- const auto game_id = game->GetGameID();
- const auto revision = game->GetRevision();
- Common::IniFile globalIni;
- for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision))
- globalIni.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true);
- Common::IniFile localIni;
- for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision))
- localIni.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true);
-
- m_codes_synced_players = 0;
-
- {
- sf::Packet pac;
- pac << MessageID::SyncCodes;
- pac << SyncCodeID::Notify;
- SendAsyncToClients(std::move(pac));
- }
-
- {
-
- std::vector<Gecko::GeckoCode> s_active_codes =
- Gecko::SetAndReturnActiveCodes(Gecko::LoadCodes(globalIni, localIni));
-
- u16 codelines = 0;
- for (const Gecko::GeckoCode& active_code : s_active_codes)
- {
- INFO_LOG_FMT(NETPLAY, "Indexing {}", active_code.name);
- for (const Gecko::GeckoCode::Code& code : active_code.codes)
- {
- INFO_LOG_FMT(NETPLAY, "{:08x} {:08x}", code.address, code.data);
- codelines++;
- }
- }
-
- INFO_LOG_FMT(NETPLAY, "Sending {} Gecko codelines", codelines);
-
- {
- sf::Packet pac;
- pac << MessageID::SyncCodes;
- pac << SyncCodeID::NotifyGecko;
- pac << codelines;
- SendAsyncToClients(std::move(pac));
- }
-
- {
- sf::Packet pac;
- pac << MessageID::SyncCodes;
- pac << SyncCodeID::GeckoData;
-
- for (const Gecko::GeckoCode& active_code : s_active_codes)
- {
- INFO_LOG_FMT(NETPLAY, "Sending {}", active_code.name);
- for (const Gecko::GeckoCode::Code& code : active_code.codes)
- {
- INFO_LOG_FMT(NETPLAY, "{:08x} {:08x}", code.address, code.data);
- pac << code.address;
- pac << code.data;
- }
- }
- SendAsyncToClients(std::move(pac));
- }
- }
-
- {
-
- std::vector<ActionReplay::ARCode> s_active_codes =
- ActionReplay::ApplyAndReturnCodes(ActionReplay::LoadCodes(globalIni, localIni));
-
- u16 codelines = 0;
- for (const ActionReplay::ARCode& active_code : s_active_codes)
- {
- INFO_LOG_FMT(NETPLAY, "Indexing {}", active_code.name);
- for (const ActionReplay::AREntry& op : active_code.ops)
- {
- INFO_LOG_FMT(NETPLAY, "{:08x} {:08x}", op.cmd_addr, op.value);
- codelines++;
- }
- }
-
- INFO_LOG_FMT(NETPLAY, "Sending {} AR codelines", codelines);
-
- {
- sf::Packet pac;
- pac << MessageID::SyncCodes;
- pac << SyncCodeID::NotifyAR;
- pac << codelines;
- SendAsyncToClients(std::move(pac));
- }
-
- {
- sf::Packet pac;
- pac << MessageID::SyncCodes;
- pac << SyncCodeID::ARData;
-
- for (const ActionReplay::ARCode& active_code : s_active_codes)
- {
- INFO_LOG_FMT(NETPLAY, "Sending {}", active_code.name);
- for (const ActionReplay::AREntry& op : active_code.ops)
- {
- INFO_LOG_FMT(NETPLAY, "{:08x} {:08x}", op.cmd_addr, op.value);
- pac << op.cmd_addr;
- pac << op.value;
- }
- }
- SendAsyncToClients(std::move(pac));
- }
- }
- return true;
- }
- void NetPlayServer::CheckSyncAndStartGame()
- {
- if (m_saves_synced && m_codes_synced)
- {
- INFO_LOG_FMT(NETPLAY, "Synchronized, starting game.");
- StartGame();
- }
- else
- {
- INFO_LOG_FMT(NETPLAY, "Not synchronized.");
- }
- }
- u64 NetPlayServer::GetInitialNetPlayRTC() const
- {
- if (Config::Get(Config::MAIN_CUSTOM_RTC_ENABLE))
- return Config::Get(Config::MAIN_CUSTOM_RTC_VALUE);
- return Common::Timer::GetLocalTimeSinceJan1970();
- }
- void NetPlayServer::SendToClients(const sf::Packet& packet, const PlayerId skip_pid,
- const u8 channel_id)
- {
- for (auto& p : m_players)
- {
- if (p.second.pid && p.second.pid != skip_pid)
- {
- Send(p.second.socket, packet, channel_id);
- }
- }
- }
- void NetPlayServer::Send(ENetPeer* socket, const sf::Packet& packet, const u8 channel_id)
- {
- Common::ENet::SendPacket(socket, packet, channel_id);
- }
- void NetPlayServer::KickPlayer(PlayerId player)
- {
- for (auto& current_player : m_players)
- {
- if (current_player.second.pid == player)
- {
- enet_peer_disconnect(current_player.second.socket, 0);
- return;
- }
- }
- }
- bool NetPlayServer::PlayerHasControllerMapped(const PlayerId pid) const
- {
- const auto mapping_matches_player_id = [pid](const PlayerId& mapping) { return mapping == pid; };
- return std::any_of(m_pad_map.begin(), m_pad_map.end(), mapping_matches_player_id) ||
- std::any_of(m_wiimote_map.begin(), m_wiimote_map.end(), mapping_matches_player_id);
- }
- void NetPlayServer::AssignNewUserAPad(const Client& player)
- {
- for (PlayerId& mapping : m_pad_map)
- {
-
- if (mapping == 0)
- {
- mapping = player.pid;
- break;
- }
- }
- }
- PlayerId NetPlayServer::GiveFirstAvailableIDTo(ENetPeer* player)
- {
- PlayerId pid = 1;
- for (auto i = m_players.begin(); i != m_players.end(); ++i)
- {
- if (i->second.pid == pid)
- {
- pid++;
- i = m_players.begin();
- }
- }
- player->data = new PlayerId(pid);
- return pid;
- }
- template <typename... Data>
- void NetPlayServer::SendResponseToPlayer(const Client& player, const MessageID message_id,
- Data&&... data_to_send)
- {
- sf::Packet response;
- response << message_id;
-
- (response << ... << std::forward<Data>(data_to_send));
- Send(player.socket, response);
- }
- template <typename... Data>
- void NetPlayServer::SendResponseToAllPlayers(const MessageID message_id, Data&&... data_to_send)
- {
- sf::Packet response;
- response << message_id;
-
- (response << ... << std::forward<Data>(data_to_send));
- SendToClients(response);
- }
- u16 NetPlayServer::GetPort() const
- {
- return m_server->address.port;
- }
- std::unordered_set<std::string> NetPlayServer::GetInterfaceSet() const
- {
- std::unordered_set<std::string> result;
- for (const auto& list_entry : GetInterfaceListInternal())
- result.emplace(list_entry.first);
- return result;
- }
- std::string NetPlayServer::GetInterfaceHost(const std::string& inter) const
- {
- char buf[16]{};
- fmt::format_to_n(buf, sizeof(buf) - 1, ":{}", GetPort());
- auto lst = GetInterfaceListInternal();
- for (const auto& list_entry : lst)
- {
- if (list_entry.first == inter)
- {
- return list_entry.second + buf;
- }
- }
- return "?";
- }
- std::vector<std::pair<std::string, std::string>> NetPlayServer::GetInterfaceListInternal() const
- {
- std::vector<std::pair<std::string, std::string>> result;
- #if defined(_WIN32)
- #elif defined(ANDROID)
- #else
- ifaddrs* ifp = nullptr;
- char buf[512];
- if (getifaddrs(&ifp) != -1)
- {
- for (ifaddrs* curifp = ifp; curifp; curifp = curifp->ifa_next)
- {
- sockaddr* sa = curifp->ifa_addr;
- if (sa == nullptr)
- continue;
- if (sa->sa_family != AF_INET)
- continue;
- sockaddr_in* sai = (struct sockaddr_in*)sa;
- if (ntohl(((struct sockaddr_in*)sa)->sin_addr.s_addr) == 0x7f000001)
- continue;
- const char* ip = inet_ntop(sa->sa_family, &sai->sin_addr, buf, sizeof(buf));
- if (ip == nullptr)
- continue;
- result.emplace_back(std::make_pair(curifp->ifa_name, ip));
- }
- freeifaddrs(ifp);
- }
- #endif
- if (result.empty())
- result.emplace_back(std::make_pair("!local!", "127.0.0.1"));
- return result;
- }
- void NetPlayServer::ChunkedDataThreadFunc()
- {
- INFO_LOG_FMT(NETPLAY, "Starting Chunked Data Thread.");
- while (m_do_loop)
- {
- m_chunked_data_event.Wait();
- if (m_abort_chunked_data)
- {
-
- while (!m_chunked_data_queue.Empty())
- m_chunked_data_queue.Pop();
- m_abort_chunked_data = false;
- }
- while (!m_chunked_data_queue.Empty())
- {
- if (!m_do_loop)
- return;
- if (m_abort_chunked_data)
- break;
- auto& e = m_chunked_data_queue.Front();
- const u32 id = m_next_chunked_data_id++;
- m_chunked_data_complete_count[id] = 0;
- size_t player_count;
- {
- std::vector<int> players;
- if (e.target_mode == TargetMode::Only)
- {
- players.push_back(e.target_pid);
- }
- else
- {
- for (auto& pl : m_players)
- {
- if (pl.second.pid != e.target_pid)
- players.push_back(pl.second.pid);
- }
- }
- player_count = players.size();
- INFO_LOG_FMT(NETPLAY, "Informing players {} of data chunk {} start.",
- fmt::join(players, ", "), id);
- sf::Packet pac;
- pac << MessageID::ChunkedDataStart;
- pac << id << e.title << sf::Uint64{e.packet.getDataSize()};
- ChunkedDataSend(std::move(pac), e.target_pid, e.target_mode);
- if (e.target_mode == TargetMode::AllExcept && e.target_pid == 1)
- m_dialog->ShowChunkedProgressDialog(e.title, e.packet.getDataSize(), players);
- }
- const bool enable_limit = Config::Get(Config::NETPLAY_ENABLE_CHUNKED_UPLOAD_LIMIT);
- const float bytes_per_second =
- (std::max(Config::Get(Config::NETPLAY_CHUNKED_UPLOAD_LIMIT), 1u) / 8.0f) * 1024.0f;
- const std::chrono::duration<double> send_interval(CHUNKED_DATA_UNIT_SIZE / bytes_per_second);
- bool skip_wait = false;
- size_t index = 0;
- do
- {
- if (!m_do_loop)
- return;
- if (m_abort_chunked_data)
- {
- INFO_LOG_FMT(NETPLAY, "Informing players of data chunk {} abort.", id);
- sf::Packet pac;
- pac << MessageID::ChunkedDataAbort;
- pac << id;
- ChunkedDataSend(std::move(pac), e.target_pid, e.target_mode);
- break;
- }
- if (e.target_mode == TargetMode::Only)
- {
- if (!m_players.contains(e.target_pid))
- {
- skip_wait = true;
- break;
- }
- }
- auto start = std::chrono::steady_clock::now();
- sf::Packet pac;
- pac << MessageID::ChunkedDataPayload;
- pac << id;
- size_t len = std::min(CHUNKED_DATA_UNIT_SIZE, e.packet.getDataSize() - index);
- pac.append(static_cast<const u8*>(e.packet.getData()) + index, len);
- INFO_LOG_FMT(NETPLAY, "Sending data chunk of {} ({} bytes at {}/{}).", id, len, index,
- e.packet.getDataSize());
- ChunkedDataSend(std::move(pac), e.target_pid, e.target_mode);
- index += CHUNKED_DATA_UNIT_SIZE;
- if (enable_limit)
- {
- std::chrono::duration<double> delta = std::chrono::steady_clock::now() - start;
- std::this_thread::sleep_for(send_interval - delta);
- }
- } while (index < e.packet.getDataSize());
- if (!m_abort_chunked_data)
- {
- INFO_LOG_FMT(NETPLAY, "Informing players of data chunk {} end.", id);
- sf::Packet pac;
- pac << MessageID::ChunkedDataEnd;
- pac << id;
- ChunkedDataSend(std::move(pac), e.target_pid, e.target_mode);
- }
- while (m_chunked_data_complete_count[id] < player_count && m_do_loop &&
- !m_abort_chunked_data && !skip_wait)
- m_chunked_data_complete_event.Wait();
- m_chunked_data_complete_count.erase(id);
- m_dialog->HideChunkedProgressDialog();
- m_chunked_data_queue.Pop();
- }
- }
- INFO_LOG_FMT(NETPLAY, "Stopping Chunked Data Thread.");
- }
- void NetPlayServer::ChunkedDataSend(sf::Packet&& packet, const PlayerId pid,
- const TargetMode target_mode)
- {
- if (target_mode == TargetMode::Only)
- {
- SendAsync(std::move(packet), pid, CHUNKED_DATA_CHANNEL);
- }
- else
- {
- SendAsyncToClients(std::move(packet), pid, CHUNKED_DATA_CHANNEL);
- }
- }
- void NetPlayServer::ChunkedDataAbort()
- {
- m_abort_chunked_data = true;
- m_chunked_data_event.Set();
- m_chunked_data_complete_event.Set();
- }
- }
|