diff --git a/dep/ggpo-x/ggpo-x.vcxproj b/dep/ggpo-x/ggpo-x.vcxproj index 499cf85ac..0db68f9b3 100644 --- a/dep/ggpo-x/ggpo-x.vcxproj +++ b/dep/ggpo-x/ggpo-x.vcxproj @@ -14,11 +14,9 @@ - - @@ -34,10 +32,8 @@ - - diff --git a/dep/ggpo-x/ggpo-x.vcxproj.filters b/dep/ggpo-x/ggpo-x.vcxproj.filters index 6f2e6dfd4..9fd65a704 100644 --- a/dep/ggpo-x/ggpo-x.vcxproj.filters +++ b/dep/ggpo-x/ggpo-x.vcxproj.filters @@ -6,9 +6,7 @@ - - @@ -32,9 +30,6 @@ network - - network - @@ -42,9 +37,7 @@ - - @@ -59,9 +52,6 @@ network - - network - diff --git a/dep/ggpo-x/include/ggponet.h b/dep/ggpo-x/include/ggponet.h index 8888d3372..6da527395 100644 --- a/dep/ggpo-x/include/ggponet.h +++ b/dep/ggpo-x/include/ggponet.h @@ -8,6 +8,8 @@ #ifndef _GGPONET_H_ #define _GGPONET_H_ +#include "enet/enet.h" + #ifdef __cplusplus extern "C" { #endif @@ -78,8 +80,7 @@ typedef struct GGPOPlayer { struct { } local; struct { - char ip_address[32]; - unsigned short port; + ENetPeer* peer; } remote; } u; } GGPOPlayer; @@ -153,8 +154,7 @@ typedef enum { GGPO_EVENTCODE_TIMESYNC = 1005, GGPO_EVENTCODE_CONNECTION_INTERRUPTED = 1006, GGPO_EVENTCODE_CONNECTION_RESUMED = 1007, - GGPO_EVENTCODE_CHAT = 1008, - GGPO_EVENTCODE_DESYNC = 1009 + GGPO_EVENTCODE_DESYNC = 1008 } GGPOEventCode; /* @@ -190,10 +190,6 @@ typedef struct { struct { GGPOPlayerHandle player; } connection_resumed; - struct { - int senderID; - const char* msg; - } chat; struct { int nFrameOfDesync; uint32_t ourCheckSum; @@ -480,25 +476,6 @@ GGPO_API GGPOErrorCode __cdecl ggpo_add_local_input(GGPOSession *, GGPOPlayerHandle player, void *values, int size); -/* - * ggpo_add_local_input -- - * - * Used to notify GGPO.net of inputs that should be trasmitted to remote - * players. ggpo_add_local_input must be called once every frame for - * all player of type GGPO_PLAYERTYPE_LOCAL. - * - * player - The player handle returned for this player when you called - * ggpo_add_local_player. - * - * values - The controller inputs for this player. - * - * size - The size of the controller inputs. This must be exactly equal to the - * size passed into ggpo_start_session. - */ - -GGPO_API GGPOErrorCode __cdecl ggpo_client_chat(GGPOSession *, - const char* message); - /* * ggpo_synchronize_input -- * @@ -575,15 +552,6 @@ GGPO_API GGPOErrorCode __cdecl ggpo_get_network_stats(GGPOSession *, GGPO_API GGPOErrorCode __cdecl ggpo_set_disconnect_timeout(GGPOSession *, int timeout); /* - * ggpo_enable_manual_network_polling -- - * - * disables polling done by ggpo and it's expected that ggpo_poll_network will be used instead. - * - */ - -GGPO_API GGPOErrorCode __cdecl ggpo_set_manual_network_polling(GGPOSession*, - bool value); - /* * ggpo_set_disconnect_notify_start -- * * The time to wait before the first GGPO_EVENTCODE_NETWORK_INTERRUPTED timeout @@ -594,14 +562,12 @@ GGPO_API GGPOErrorCode __cdecl ggpo_set_manual_network_polling(GGPOSession*, */ GGPO_API GGPOErrorCode __cdecl ggpo_set_disconnect_notify_start(GGPOSession *, int timeout); -/* -* ggpo_poll_network -- -* -* polls the network socket for any messages to be sent and recieved. -* -*/ -GGPO_API GGPOErrorCode __cdecl ggpo_poll_network(GGPOSession*); +/* + * ENet packet processing + */ +GGPO_API GGPOErrorCode __cdecl ggpo_handle_packet(GGPOSession*, + ENetPeer* peer, const ENetPacket* pkt); /* * ggpo_log -- diff --git a/dep/ggpo-x/src/backends/backend.h b/dep/ggpo-x/src/backends/backend.h index 7b747e0ae..6296a1128 100644 --- a/dep/ggpo-x/src/backends/backend.h +++ b/dep/ggpo-x/src/backends/backend.h @@ -20,16 +20,14 @@ public: virtual GGPOErrorCode SyncInput(void *values, int size, int *disconnect_flags) = 0; virtual GGPOErrorCode IncrementFrame(uint16_t checksum) = 0; virtual GGPOErrorCode CurrentFrame(int& current) =0; - virtual GGPOErrorCode Chat(const char* text) = 0;// { return GGPO_OK; } virtual GGPOErrorCode DisconnectPlayer(GGPOPlayerHandle handle) = 0;// { return GGPO_OK; } - virtual GGPOErrorCode PollNetwork() = 0; virtual GGPOErrorCode GetNetworkStats(GGPONetworkStats *stats, GGPOPlayerHandle handle) { return GGPO_OK; } virtual GGPOErrorCode Logv(const char *fmt, va_list list) { ::Logv(fmt, list); return GGPO_OK; } virtual GGPOErrorCode SetFrameDelay(GGPOPlayerHandle player, int delay) { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode SetDisconnectTimeout(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode SetDisconnectNotifyStart(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; } - virtual GGPOErrorCode SetManualNetworkPolling(bool value) = 0; + virtual GGPOErrorCode OnPacket(ENetPeer* peer, const ENetPacket* pkt) = 0; }; diff --git a/dep/ggpo-x/src/backends/p2p.cpp b/dep/ggpo-x/src/backends/p2p.cpp index ce3fdcc58..dbffe9d67 100644 --- a/dep/ggpo-x/src/backends/p2p.cpp +++ b/dep/ggpo-x/src/backends/p2p.cpp @@ -27,7 +27,6 @@ Peer2PeerBackend::Peer2PeerBackend(GGPOSessionCallbacks *cb, _callbacks = *cb; _synchronizing = true; _next_recommended_sleep = 0; - _manual_network_polling = false; /* * Initialize the synchronziation layer @@ -39,11 +38,6 @@ Peer2PeerBackend::Peer2PeerBackend(GGPOSessionCallbacks *cb, config.num_prediction_frames = nframes; _sync.Init(config); - /* - * Initialize the UDP port - */ - _udp.Init(localport, &_poll, this); - _endpoints.resize(_num_players); memset(_local_connect_status, 0, sizeof(_local_connect_status)); for (int i = 0; i < ARRAY_SIZE(_local_connect_status); i++) { @@ -61,23 +55,20 @@ Peer2PeerBackend::~Peer2PeerBackend() } void -Peer2PeerBackend::AddRemotePlayer(char *ip, - uint16 port, - int queue) +Peer2PeerBackend::AddRemotePlayer(ENetPeer* peer, int queue) { /* * Start the state machine (xxx: no) */ _synchronizing = true; - _endpoints[queue].Init(&_udp, _poll, queue, ip, port, _local_connect_status); + _endpoints[queue].Init(peer, queue, _local_connect_status); _endpoints[queue].SetDisconnectTimeout(_disconnect_timeout); _endpoints[queue].SetDisconnectNotifyStart(_disconnect_notify_start); _endpoints[queue].Synchronize(); } -GGPOErrorCode Peer2PeerBackend::AddSpectator(char *ip, - uint16 port) +GGPOErrorCode Peer2PeerBackend::AddSpectator(ENetPeer* peer) { if (_num_spectators == GGPO_MAX_SPECTATORS) { return GGPO_ERRORCODE_TOO_MANY_SPECTATORS; @@ -90,7 +81,7 @@ GGPOErrorCode Peer2PeerBackend::AddSpectator(char *ip, } int queue = _num_spectators++; - _spectators[queue].Init(&_udp, _poll, queue + 1000, ip, port, _local_connect_status); + _spectators[queue].Init(peer, queue + 1000, _local_connect_status); _spectators[queue].SetDisconnectTimeout(_disconnect_timeout); _spectators[queue].SetDisconnectNotifyStart(_disconnect_notify_start); _spectators[queue].Synchronize(); @@ -155,20 +146,10 @@ void Peer2PeerBackend::CheckDesync() GGPOErrorCode Peer2PeerBackend::DoPoll() { - // Pass on chat - for (int i = 0; i < _num_players; i++) { - _endpoints[i].ConsumeChat([&](const char* msg) { - GGPOEvent info; - info.u.chat.senderID = i; - info.code = GGPO_EVENTCODE_CHAT; - info.u.chat.msg = msg; - _callbacks.on_event(_callbacks.context, &info); - }); - } - - if (!_sync.InRollback()) { - if (!_manual_network_polling) - _poll.Pump(0); + if (!_sync.InRollback()) + { + for (UdpProtocol& udp : _endpoints) + udp.OnLoopPoll(); PollUdpProtocolEvents(); CheckDesync(); @@ -309,7 +290,7 @@ Peer2PeerBackend::AddPlayer(GGPOPlayer *player, GGPOPlayerHandle *handle) { if (player->type == GGPO_PLAYERTYPE_SPECTATOR) { - return AddSpectator(player->u.remote.ip_address, player->u.remote.port); + return AddSpectator(player->u.remote.peer); } int queue = player->player_num - 1; @@ -319,7 +300,7 @@ Peer2PeerBackend::AddPlayer(GGPOPlayer *player, *handle = QueueToPlayerHandle(queue); if (player->type == GGPO_PLAYERTYPE_REMOTE) { - AddRemotePlayer(player->u.remote.ip_address, player->u.remote.port, queue); + AddRemotePlayer(player->u.remote.peer, queue); } return GGPO_OK; } @@ -413,19 +394,6 @@ Peer2PeerBackend::CurrentFrame(int& current) return GGPO_OK; } -GGPOErrorCode -Peer2PeerBackend::PollNetwork() -{ - _poll.Pump(0); - return GGPO_OK; -} - -GGPOErrorCode Peer2PeerBackend::SetManualNetworkPolling(bool value) -{ - _manual_network_polling = value; - return GGPO_OK; -} - GGPOErrorCode Peer2PeerBackend::IncrementFrame(uint16_t checksum1) { @@ -766,21 +734,6 @@ Peer2PeerBackend::SetDisconnectNotifyStart(int timeout) return GGPO_OK; } -GGPOErrorCode -Peer2PeerBackend::Chat(const char* text) -{ - if (strlen(text) >= MAX_CHAT_LENGTH) - return GGPO_CHAT_MESSAGE_TOO_LONG; - - // Send the input to all the remote players. - for (int i = 0; i < _num_players; i++) { - if (_endpoints[i].IsInitialized()) { - _endpoints[i].SendChat(text); - } - } - return GGPO_OK; -} - GGPOErrorCode Peer2PeerBackend::PlayerHandleToQueue(GGPOPlayerHandle player, int *queue) { @@ -793,21 +746,27 @@ Peer2PeerBackend::PlayerHandleToQueue(GGPOPlayerHandle player, int *queue) } -void -Peer2PeerBackend::OnMsg(sockaddr_in &from, UdpMsg *msg, int len) +GGPOErrorCode +Peer2PeerBackend::OnPacket(ENetPeer* peer, const ENetPacket* pkt) { + // ugh why is const so hard for some people... + UdpMsg* msg = const_cast(reinterpret_cast(pkt->data)); + const int len = static_cast(pkt->dataLength); + for (int i = 0; i < _num_players; i++) { - if (_endpoints[i].HandlesMsg(from, msg)) { + if (_endpoints[i].GetENetPeer() == peer) { _endpoints[i].OnMsg(msg, len); - return; + return GGPO_OK; } } for (int i = 0; i < _num_spectators; i++) { - if (_spectators[i].HandlesMsg(from, msg)) { + if (_spectators[i].GetENetPeer() == peer) { _spectators[i].OnMsg(msg, len); - return; + return GGPO_OK; } } + + return GGPO_ERRORCODE_INVALID_PLAYER_HANDLE; } void diff --git a/dep/ggpo-x/src/backends/p2p.h b/dep/ggpo-x/src/backends/p2p.h index 7835a0cb9..3e3220a6b 100644 --- a/dep/ggpo-x/src/backends/p2p.h +++ b/dep/ggpo-x/src/backends/p2p.h @@ -9,13 +9,13 @@ #define _P2P_H #include "types.h" -#include "poll.h" #include "sync.h" #include "backend.h" #include "timesync.h" #include "network/udp_proto.h" #include -class Peer2PeerBackend : public GGPOSession, Udp::Callbacks { +class Peer2PeerBackend final : public GGPOSession +{ public: Peer2PeerBackend(GGPOSessionCallbacks *cb, const char *gamename, uint16 localport, int num_players, int input_size, int nframes); virtual ~Peer2PeerBackend(); @@ -32,13 +32,8 @@ public: virtual GGPOErrorCode SetFrameDelay(GGPOPlayerHandle player, int delay) override; virtual GGPOErrorCode SetDisconnectTimeout(int timeout) override; virtual GGPOErrorCode SetDisconnectNotifyStart(int timeout) override; - virtual GGPOErrorCode Chat(const char* text) override; virtual GGPOErrorCode CurrentFrame(int& current) override; - virtual GGPOErrorCode PollNetwork() override; - virtual GGPOErrorCode SetManualNetworkPolling(bool value) override; - - public: - virtual void OnMsg(sockaddr_in &from, UdpMsg *msg, int len); + virtual GGPOErrorCode OnPacket(ENetPeer* peer, const ENetPacket* pkt) override; protected: GGPOErrorCode PlayerHandleToQueue(GGPOPlayerHandle player, int *queue); @@ -50,8 +45,8 @@ protected: void CheckInitialSync(void); int Poll2Players(int current_frame); int PollNPlayers(int current_frame); - void AddRemotePlayer(char *remoteip, uint16 reportport, int queue); - GGPOErrorCode AddSpectator(char *remoteip, uint16 reportport); + void AddRemotePlayer(ENetPeer* peer, int queue); + GGPOErrorCode AddSpectator(ENetPeer* peer); virtual void OnSyncEvent(Sync::Event &e) { } virtual void OnUdpProtocolEvent(UdpProtocol::Event &e, GGPOPlayerHandle handle); virtual void OnUdpProtocolPeerEvent(UdpProtocol::Event &e, int queue); @@ -59,9 +54,7 @@ protected: protected: GGPOSessionCallbacks _callbacks; - Poll _poll; Sync _sync; - Udp _udp; std::vector _endpoints; UdpProtocol _spectators[GGPO_MAX_SPECTATORS]; int _num_spectators; @@ -75,8 +68,6 @@ protected: int _disconnect_timeout; int _disconnect_notify_start; - bool _manual_network_polling; - UdpMsg::connect_status _local_connect_status[UDP_MSG_MAX_PLAYERS]; struct ChecksumEntry { int nFrame; diff --git a/dep/ggpo-x/src/backends/spectator.cpp b/dep/ggpo-x/src/backends/spectator.cpp index 71ca42519..c8c667c3f 100644 --- a/dep/ggpo-x/src/backends/spectator.cpp +++ b/dep/ggpo-x/src/backends/spectator.cpp @@ -20,7 +20,6 @@ SpectatorBackend::SpectatorBackend(GGPOSessionCallbacks *cb, { _callbacks = *cb; _synchronizing = true; - _manual_network_polling = false; for (int i = 0; i < ARRAY_SIZE(_inputs); i++) { _inputs[i].frame = -1; @@ -29,12 +28,14 @@ SpectatorBackend::SpectatorBackend(GGPOSessionCallbacks *cb, /* * Initialize the UDP port */ - _udp.Init(localport, &_poll, this); + // FIXME + abort(); + //_udp.Init(localport, &_poll, this); /* * Init the host endpoint */ - _host.Init(&_udp, _poll, 0, hostip, hostport, NULL); + //_host.Init(&_udp, _poll, 0, hostip, hostport, NULL); _host.Synchronize(); /* @@ -50,9 +51,6 @@ SpectatorBackend::~SpectatorBackend() GGPOErrorCode SpectatorBackend::DoPoll() { - if (!_manual_network_polling) - _poll.Pump(0); - PollUdpProtocolEvents(); return GGPO_OK; } @@ -95,20 +93,6 @@ SpectatorBackend::CurrentFrame(int& current) return GGPO_OK; } -GGPOErrorCode -SpectatorBackend::PollNetwork() -{ - _poll.Pump(0); - return GGPO_OK; -} - -GGPOErrorCode -SpectatorBackend::SetManualNetworkPolling(bool value) -{ - _manual_network_polling = value; - return GGPO_OK; -} - GGPOErrorCode SpectatorBackend::IncrementFrame(uint16_t checksum) { @@ -188,11 +172,14 @@ SpectatorBackend::OnUdpProtocolEvent(UdpProtocol::Event &evt) } } -void -SpectatorBackend::OnMsg(sockaddr_in &from, UdpMsg *msg, int len) +GGPOErrorCode SpectatorBackend::OnPacket(ENetPeer* peer, const ENetPacket* pkt) { - if (_host.HandlesMsg(from, msg)) { - _host.OnMsg(msg, len); - } + if (_host.GetENetPeer() != peer) + return GGPO_ERRORCODE_INVALID_PLAYER_HANDLE; + + UdpMsg* msg = const_cast(reinterpret_cast(pkt->data)); + const int len = static_cast(pkt->dataLength); + _host.OnMsg(msg, len); + return GGPO_OK; } diff --git a/dep/ggpo-x/src/backends/spectator.h b/dep/ggpo-x/src/backends/spectator.h index 255fb4231..cc5d30444 100644 --- a/dep/ggpo-x/src/backends/spectator.h +++ b/dep/ggpo-x/src/backends/spectator.h @@ -9,7 +9,6 @@ #define _SPECTATOR_H #include "types.h" -#include "poll.h" #include "sync.h" #include "backend.h" #include "timesync.h" @@ -17,7 +16,7 @@ #define SPECTATOR_FRAME_BUFFER_SIZE 64 -class SpectatorBackend : public GGPOSession, Udp::Callbacks { +class SpectatorBackend final : public GGPOSession { public: SpectatorBackend(GGPOSessionCallbacks *cb, const char *gamename, uint16 localport, int num_players, int input_size, char *hostip, u_short hostport); virtual ~SpectatorBackend(); @@ -34,13 +33,8 @@ public: virtual GGPOErrorCode SetFrameDelay(GGPOPlayerHandle player, int delay) { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode SetDisconnectTimeout(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode SetDisconnectNotifyStart(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; } - virtual GGPOErrorCode Chat(const char* text) override { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode CurrentFrame(int& current) override; - virtual GGPOErrorCode PollNetwork() override; - virtual GGPOErrorCode SetManualNetworkPolling(bool value) override; - -public: - virtual void OnMsg(sockaddr_in &from, UdpMsg *msg, int len); + virtual GGPOErrorCode OnPacket(ENetPeer* peer, const ENetPacket* pkt) override; protected: void PollUdpProtocolEvents(void); @@ -50,15 +44,12 @@ protected: protected: GGPOSessionCallbacks _callbacks; - Poll _poll; - Udp _udp; UdpProtocol _host; bool _synchronizing; int _input_size; int _num_players; int _next_input_to_send; GameInput _inputs[SPECTATOR_FRAME_BUFFER_SIZE]; - bool _manual_network_polling; }; #endif diff --git a/dep/ggpo-x/src/backends/synctest.h b/dep/ggpo-x/src/backends/synctest.h index 8339dadf4..95ffec59a 100644 --- a/dep/ggpo-x/src/backends/synctest.h +++ b/dep/ggpo-x/src/backends/synctest.h @@ -13,7 +13,7 @@ #include "sync.h" #include "ring_buffer.h" -class SyncTestBackend : public GGPOSession { +class SyncTestBackend final : public GGPOSession { public: SyncTestBackend(GGPOSessionCallbacks *cb, char *gamename, int frames, int num_players); virtual ~SyncTestBackend(); @@ -25,10 +25,8 @@ public: virtual GGPOErrorCode IncrementFrame(uint16_t checksum); virtual GGPOErrorCode Logv(char *fmt, va_list list); virtual GGPOErrorCode DisconnectPlayer(GGPOPlayerHandle handle) { return GGPO_OK; } - virtual GGPOErrorCode Chat(const char* text) override { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode CurrentFrame(int& current) override; - virtual GGPOErrorCode PollNetwork() override { return GGPO_OK; }; - virtual GGPOErrorCode SetManualNetworkPolling(bool value) override { return GGPO_OK; }; + virtual GGPOErrorCode OnPacket(ENetPeer* peer, const ENetPacket* pkt) override { return GGPO_ERRORCODE_UNSUPPORTED; } protected: struct SavedInfo { diff --git a/dep/ggpo-x/src/main.cpp b/dep/ggpo-x/src/main.cpp index 0ed0b9ad2..de7c853f0 100644 --- a/dep/ggpo-x/src/main.cpp +++ b/dep/ggpo-x/src/main.cpp @@ -151,15 +151,6 @@ ggpo_get_current_frame(GGPOSession *ggpo, int& nFrame) return ggpo->CurrentFrame(nFrame); } -GGPOErrorCode -ggpo_client_chat(GGPOSession *ggpo, const char *text) -{ - if (!ggpo) { - return GGPO_ERRORCODE_INVALID_SESSION; - } - return ggpo->Chat(text); -} - GGPOErrorCode ggpo_get_network_stats(GGPOSession *ggpo, GGPOPlayerHandle player, @@ -172,6 +163,13 @@ ggpo_get_network_stats(GGPOSession *ggpo, } +GGPOErrorCode ggpo_handle_packet(GGPOSession* ggpo, ENetPeer* peer, const ENetPacket* pkt) +{ + if (!ggpo) + return GGPO_ERRORCODE_INVALID_SESSION; + return ggpo->OnPacket(peer, pkt); +} + GGPOErrorCode ggpo_close_session(GGPOSession *ggpo) { @@ -191,16 +189,6 @@ ggpo_set_disconnect_timeout(GGPOSession *ggpo, int timeout) return ggpo->SetDisconnectTimeout(timeout); } -GGPOErrorCode -ggpo_set_manual_network_polling(GGPOSession *ggpo, bool value) -{ - if (!ggpo) - { - return GGPO_ERRORCODE_INVALID_SESSION; - } - return ggpo->SetManualNetworkPolling(value); -} - GGPOErrorCode ggpo_set_disconnect_notify_start(GGPOSession *ggpo, int timeout) { @@ -210,16 +198,6 @@ ggpo_set_disconnect_notify_start(GGPOSession *ggpo, int timeout) return ggpo->SetDisconnectNotifyStart(timeout); } -GGPOErrorCode -ggpo_poll_network(GGPOSession* ggpo) -{ - if (!ggpo) - { - return GGPO_ERRORCODE_INVALID_SESSION; - } - return ggpo->PollNetwork(); -} - GGPOErrorCode ggpo_start_spectating(GGPOSession **session, GGPOSessionCallbacks *cb, const char *game, @@ -238,4 +216,3 @@ GGPOErrorCode ggpo_start_spectating(GGPOSession **session, host_port); return GGPO_OK; } - diff --git a/dep/ggpo-x/src/network/udp.cpp b/dep/ggpo-x/src/network/udp.cpp deleted file mode 100644 index 5c2250470..000000000 --- a/dep/ggpo-x/src/network/udp.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* ----------------------------------------------------------------------- - * GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC. - * - * Use of this software is governed by the MIT license that can be found - * in the LICENSE file. - */ - -#include "types.h" -#include "udp.h" - -SOCKET -CreateSocket(uint16 bind_port, int retries) -{ - SOCKET s; - sockaddr_in sin; - uint16 port; - int optval = 1; - - s = socket(AF_INET, SOCK_DGRAM, 0); - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&optval, sizeof optval); - setsockopt(s, SOL_SOCKET, SO_DONTLINGER, (const char *)&optval, sizeof optval); - - // non-blocking... - u_long iMode = 1; - ioctlsocket(s, FIONBIO, &iMode); - - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(INADDR_ANY); - for (port = bind_port; port <= bind_port + retries; port++) { - sin.sin_port = htons(port); - if (bind(s, (sockaddr *)&sin, sizeof sin) != SOCKET_ERROR) { - Log("Udp bound to port: %d.\n", port); - return s; - } - } - closesocket(s); - return INVALID_SOCKET; -} - -Udp::Udp() : - _socket(INVALID_SOCKET), - _callbacks(NULL) -{ -} - -Udp::~Udp(void) -{ - if (_socket != INVALID_SOCKET) { - closesocket(_socket); - _socket = INVALID_SOCKET; - } -} - -void -Udp::Init(uint16 port, Poll *poll, Callbacks *callbacks) -{ - _callbacks = callbacks; - - _poll = poll; - _poll->RegisterLoop(this); - - Log("binding udp socket to port %d.\n", port); - _socket = CreateSocket(port, 0); -} - -void -Udp::SendTo(char *buffer, int len, int flags, struct sockaddr *dst, int destlen) -{ - struct sockaddr_in *to = (struct sockaddr_in *)dst; - - int res = sendto(_socket, buffer, len, flags, dst, destlen); - if (res == SOCKET_ERROR) { - DWORD err = WSAGetLastError(); - Log("unknown error in sendto (erro: %d wsaerr: %d).\n", res, err); - ASSERT(FALSE && "Unknown error in sendto"); - } - char dst_ip[1024]; - Log("sent packet length %d to %s:%d (ret:%d).\n", len, inet_ntop(AF_INET, (void *)&to->sin_addr, dst_ip, ARRAY_SIZE(dst_ip)), ntohs(to->sin_port), res); -} - -bool -Udp::OnLoopPoll(void *cookie) -{ - uint8 recv_buf[MAX_UDP_PACKET_SIZE]; - sockaddr_in recv_addr; - int recv_addr_len; - - for (;;) { - recv_addr_len = sizeof(recv_addr); - int len = recvfrom(_socket, (char *)recv_buf, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&recv_addr, &recv_addr_len); - - // TODO: handle len == 0... indicates a disconnect. - - if (len == -1) { - int error = WSAGetLastError(); - if (error != WSAEWOULDBLOCK) { - Log("recvfrom WSAGetLastError returned %d (%x).\n", error, error); - } - break; - } else if (len > 0) { - char src_ip[1024]; - Log("recvfrom returned (len:%d from:%s:%d).\n", len, inet_ntop(AF_INET, (void*)&recv_addr.sin_addr, src_ip, ARRAY_SIZE(src_ip)), ntohs(recv_addr.sin_port) ); - UdpMsg *msg = (UdpMsg *)recv_buf; - _callbacks->OnMsg(recv_addr, msg, len); - } - } - return true; -} - - -void -Udp::Log(const char *fmt, ...) -{ - char buf[1024]; - size_t offset; - va_list args; - - strcpy_s(buf, "udp | "); - offset = strlen(buf); - va_start(args, fmt); - vsnprintf(buf + offset, ARRAY_SIZE(buf) - offset - 1, fmt, args); - buf[ARRAY_SIZE(buf)-1] = '\0'; - ::Log(buf); - va_end(args); -} diff --git a/dep/ggpo-x/src/network/udp.h b/dep/ggpo-x/src/network/udp.h deleted file mode 100644 index c725150c1..000000000 --- a/dep/ggpo-x/src/network/udp.h +++ /dev/null @@ -1,61 +0,0 @@ -/* ----------------------------------------------------------------------- - * GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC. - * - * Use of this software is governed by the MIT license that can be found - * in the LICENSE file. - */ - -#ifndef _UDP_H -#define _UDP_H - -#include "poll.h" -#include "udp_msg.h" -#include "ggponet.h" -#include "ring_buffer.h" - -#define MAX_UDP_ENDPOINTS 16 - -static const int MAX_UDP_PACKET_SIZE = 4096; - -class Udp : public IPollSink -{ -public: - struct Stats { - int bytes_sent; - int packets_sent; - float kbps_sent; - }; - - struct Callbacks { - virtual ~Callbacks() { } - virtual void OnMsg(sockaddr_in &from, UdpMsg *msg, int len) = 0; - }; - - -protected: - void Log(const char *fmt, ...); - -public: - Udp(); - - void Init(uint16 port, Poll *p, Callbacks *callbacks); - - void SendTo(char *buffer, int len, int flags, struct sockaddr *dst, int destlen); - - bool OnLoopPoll(void *cookie) override; - -public: - ~Udp(void); - -protected: - // Network transmission information - SOCKET _socket; - - // state management - Callbacks *_callbacks; - Poll *_poll; - - -}; - -#endif diff --git a/dep/ggpo-x/src/network/udp_msg.h b/dep/ggpo-x/src/network/udp_msg.h index 1a4b6e4ff..d8ac6f349 100644 --- a/dep/ggpo-x/src/network/udp_msg.h +++ b/dep/ggpo-x/src/network/udp_msg.h @@ -10,7 +10,6 @@ #define MAX_COMPRESSED_BITS 4096 #define UDP_MSG_MAX_PLAYERS 4 -#define MAX_CHAT_LENGTH 120 #pragma pack(push, 1) struct UdpMsg @@ -24,7 +23,6 @@ struct UdpMsg QualityReply = 5, KeepAlive = 6, InputAck = 7, - Chat = 8, }; struct connect_status { @@ -75,9 +73,6 @@ struct UdpMsg struct { int ack_frame:31; } input_ack; - struct { - char msg[MAX_CHAT_LENGTH]; - } chat; } u; public: @@ -94,7 +89,6 @@ public: case QualityReport: return sizeof(u.quality_report); case QualityReply: return sizeof(u.quality_reply); case InputAck: return sizeof(u.input_ack); - case Chat: return MAX_CHAT_LENGTH; case KeepAlive: return 0; case Input: size = (int)((char *)&u.input.bits - (char *)&u.input); diff --git a/dep/ggpo-x/src/network/udp_proto.cpp b/dep/ggpo-x/src/network/udp_proto.cpp index 1197ddccb..faecdbdff 100644 --- a/dep/ggpo-x/src/network/udp_proto.cpp +++ b/dep/ggpo-x/src/network/udp_proto.cpp @@ -21,6 +21,8 @@ static const int NETWORK_STATS_INTERVAL = 500; static const int UDP_SHUTDOWN_TIMER = 5000; static const int MAX_SEQ_DISTANCE = (1 << 15); +static const uint8_t ENET_CHANNEL_ID = 1; + UdpProtocol::UdpProtocol() : _local_frame_advantage(0), _remote_frame_advantage(0), @@ -39,7 +41,7 @@ UdpProtocol::UdpProtocol() : _connected(false), _next_send_seq(0), _next_recv_seq(0), - _udp(NULL) + _peer(nullptr) { _last_sent_input.init(-1, NULL, 1); _last_received_input.init(-1, NULL, 1); @@ -50,17 +52,12 @@ UdpProtocol::UdpProtocol() : for (int i = 0; i < ARRAY_SIZE(_peer_connect_status); i++) { _peer_connect_status[i].last_frame = -1; } - memset(&_peer_addr, 0, sizeof _peer_addr); - _oo_packet.msg = NULL; - - _send_latency = Platform::GetConfigInt("ggpo.network.delay"); - _oop_percent = Platform::GetConfigInt("ggpo.oop.percent"); } UdpProtocol::~UdpProtocol() { - ClearSendQueue(); } + void UdpProtocol::SetFrameDelay(int delay) { _timesync.SetFrameDelay(delay); @@ -70,32 +67,22 @@ int UdpProtocol::RemoteFrameDelay()const { return _timesync._remoteFrameDelay; } -void -UdpProtocol::Init(Udp *udp, - Poll &poll, - int queue, - char *ip, - u_short port, - UdpMsg::connect_status *status) + +void UdpProtocol::Init(ENetPeer* peer, int queue, UdpMsg::connect_status *status) { - _udp = udp; + _peer = peer; _queue = queue; _local_connect_status = status; - _peer_addr.sin_family = AF_INET; - _peer_addr.sin_port = htons(port); - inet_pton(AF_INET, ip, &_peer_addr.sin_addr.s_addr); - do { _magic_number = (uint16)rand(); } while (_magic_number == 0); - poll.RegisterLoop(this); } void UdpProtocol::SendInput(GameInput &input) { - if (_udp) { + if (_peer) { if (_current_state == Running) { /* * Check to see if this is a good time to adjust for the rift... @@ -205,24 +192,17 @@ void UdpProtocol::EndPollLoop() if (_remoteCheckSumsThisFrame.size()) _remoteCheckSums.emplace(*_remoteCheckSumsThisFrame.rbegin()); } -void UdpProtocol::SendChat(const char* message) -{ - UdpMsg* msg = new UdpMsg(UdpMsg::Chat); - strcpy_s(msg->u.chat.msg, message); - SendMsg(msg); -} bool -UdpProtocol::OnLoopPoll(void *cookie) +UdpProtocol::OnLoopPoll() { - if (!_udp) { + if (!_peer) { return true; } unsigned int now = Platform::GetCurrentTimeMS(); unsigned int next_interval; - PumpSendQueue(); switch (_current_state) { case Syncing: next_interval = (_state.sync.roundtrips_remaining == NUM_SYNC_PACKETS) ? SYNC_FIRST_RETRY_INTERVAL : SYNC_RETRY_INTERVAL; @@ -255,11 +235,13 @@ UdpProtocol::OnLoopPoll(void *cookie) _state.running.last_network_stats_interval = now; } + // TODO: needed with enet? if (_last_send_time && _last_send_time + KEEP_ALIVE_INTERVAL < now) { Log("Sending keep alive packet\n"); SendMsg(new UdpMsg(UdpMsg::KeepAlive)); } + // These can be dropped.. if (_disconnect_timeout && _disconnect_notify_start && !_disconnect_notify_sent && (_last_recv_time + _disconnect_notify_start < now)) { Log("Endpoint has stopped receiving packets for %d ms. Sending notification.\n", _disconnect_notify_start); @@ -281,7 +263,8 @@ UdpProtocol::OnLoopPoll(void *cookie) case Disconnected: if (_shutdown_timeout < now) { Log("Shutting down udp connection.\n"); - _udp = NULL; + abort(); + _peer = NULL; _shutdown_timeout = 0; } @@ -311,28 +294,21 @@ UdpProtocol::SendSyncRequest() void UdpProtocol::SendMsg(UdpMsg *msg) { + const int size = msg->PacketSize(); LogMsg("send", msg); _packets_sent++; _last_send_time = Platform::GetCurrentTimeMS(); - _bytes_sent += msg->PacketSize(); + _bytes_sent += size; msg->hdr.magic = _magic_number; msg->hdr.sequence_number = _next_send_seq++; - _send_queue.push(QueueEntry(Platform::GetCurrentTimeMS(), _peer_addr, msg)); - PumpSendQueue(); -} - -bool -UdpProtocol::HandlesMsg(sockaddr_in &from, - UdpMsg *msg) -{ - if (!_udp) { - return false; - } - return _peer_addr.sin_addr.S_un.S_addr == from.sin_addr.S_un.S_addr && - _peer_addr.sin_port == from.sin_port; + ENetPacket* pkt = enet_packet_create(msg, size, 0); + enet_peer_send(_peer, ENET_CHANNEL_ID, pkt); + // TODO: flush packets? + // TODO: get rid of the extra heap allocation here... + delete msg; } void @@ -349,7 +325,6 @@ UdpProtocol::OnMsg(UdpMsg *msg, int len) &UdpProtocol::OnQualityReply, /* QualityReply */ &UdpProtocol::OnKeepAlive, /* KeepAlive */ &UdpProtocol::OnInputAck, /* InputAck */ - &UdpProtocol::OnChat, /* InputAck */ }; // filter out messages that don't match what we expect @@ -422,7 +397,7 @@ UdpProtocol::QueueEvent(const UdpProtocol::Event &evt) void UdpProtocol::Synchronize() { - if (_udp) { + if (_peer) { _current_state = Syncing; _state.sync.roundtrips_remaining = NUM_SYNC_PACKETS; SendSyncRequest(); @@ -479,9 +454,6 @@ UdpProtocol::LogMsg(const char *prefix, UdpMsg *msg) case UdpMsg::InputAck: Log("%s input ack.\n", prefix); break; - case UdpMsg::Chat: - Log("%s chat.\n", prefix); - break; default: Log("Unknown UdpMsg type."); } @@ -706,17 +678,6 @@ UdpProtocol::OnKeepAlive(UdpMsg *msg, int len) { return true; } -void UdpProtocol::ConsumeChat(std::function onChat) -{ - for (const auto& msg : _chatMessages) - onChat(msg.c_str()); - _chatMessages.clear(); -} -bool UdpProtocol::OnChat(UdpMsg* msg, int len) -{ - _chatMessages.push_back(msg->u.chat.msg); - return true; -} void UdpProtocol::GetNetworkStats(struct GGPONetworkStats *s) @@ -768,52 +729,3 @@ UdpProtocol::SetDisconnectNotifyStart(int timeout) { _disconnect_notify_start = timeout; } - -void -UdpProtocol::PumpSendQueue() -{ - while (!_send_queue.empty()) { - QueueEntry &entry = _send_queue.front(); - - if (_send_latency) { - // should really come up with a gaussian distributation based on the configured - // value, but this will do for now. - int jitter = (_send_latency * 2 / 3) + ((rand() % _send_latency) / 3); - if (Platform::GetCurrentTimeMS() < _send_queue.front().queue_time + jitter) { - break; - } - } - if (_oop_percent && !_oo_packet.msg && ((rand() % 100) < _oop_percent)) { - int delay = rand() % (_send_latency * 10 + 1000); - Log("creating rogue oop (seq: %d delay: %d)\n", entry.msg->hdr.sequence_number, delay); - _oo_packet.send_time = Platform::GetCurrentTimeMS() + delay; - _oo_packet.msg = entry.msg; - _oo_packet.dest_addr = entry.dest_addr; - } else { - ASSERT(entry.dest_addr.sin_addr.s_addr); - - _udp->SendTo((char *)entry.msg, entry.msg->PacketSize(), 0, - (struct sockaddr *)&entry.dest_addr, sizeof entry.dest_addr); - - delete entry.msg; - } - _send_queue.pop(); - } - if (_oo_packet.msg && _oo_packet.send_time < Platform::GetCurrentTimeMS()) { - Log("sending rogue oop!"); - _udp->SendTo((char *)_oo_packet.msg, _oo_packet.msg->PacketSize(), 0, - (struct sockaddr *)&_oo_packet.dest_addr, sizeof _oo_packet.dest_addr); - - delete _oo_packet.msg; - _oo_packet.msg = NULL; - } -} - -void -UdpProtocol::ClearSendQueue() -{ - while (!_send_queue.empty()) { - delete _send_queue.front().msg; - _send_queue.pop(); - } -} diff --git a/dep/ggpo-x/src/network/udp_proto.h b/dep/ggpo-x/src/network/udp_proto.h index 086beda1c..32ebad721 100644 --- a/dep/ggpo-x/src/network/udp_proto.h +++ b/dep/ggpo-x/src/network/udp_proto.h @@ -8,8 +8,7 @@ #ifndef _UDP_PROTO_H_ #define _UDP_PROTO_H_ -#include "poll.h" -#include "udp.h" +#include "enet/enet.h" #include "udp_msg.h" #include "game_input.h" #include "timesync.h" @@ -19,7 +18,7 @@ #include #include #include -class UdpProtocol : public IPollSink +class UdpProtocol { public: struct Stats { @@ -29,7 +28,6 @@ public: float av_remote_frame_advantage; float av_local_frame_advantage; int send_queue_len; - Udp::Stats udp; }; struct Event { @@ -62,23 +60,23 @@ public: }; public: - virtual bool OnLoopPoll(void *cookie); + bool OnLoopPoll(); public: UdpProtocol(); - virtual ~UdpProtocol(); + ~UdpProtocol(); - void Init(Udp *udp, Poll &p, int queue, char *ip, u_short port, UdpMsg::connect_status *status); + ENetPeer* GetENetPeer() const { return _peer; } + + void Init(ENetPeer* peer, int queue, UdpMsg::connect_status *status); void Synchronize(); bool GetPeerConnectStatus(int id, int *frame); - bool IsInitialized() { return _udp != NULL; } + bool IsInitialized() { return _peer != nullptr; } bool IsSynchronized() { return _current_state == Running; } bool IsRunning() { return _current_state == Running; } void SendInput(GameInput &input); - void SendChat(const char* message); void SendInputAck(); - bool HandlesMsg(sockaddr_in &from, UdpMsg *msg); void OnMsg(UdpMsg *msg, int len); void Disconnect(); @@ -90,7 +88,6 @@ public: void SetDisconnectTimeout(int timeout); void SetDisconnectNotifyStart(int timeout); void SetFrameDelay(int delay); - void ConsumeChat(std::function onChat); void ApplyToEvents(std::function cb); void StartPollLoop(); void EndPollLoop(); @@ -114,13 +111,11 @@ protected: void UpdateNetworkStats(void); void QueueEvent(const UdpProtocol::Event &evt); - void ClearSendQueue(void); void Log(const char *fmt, ...); void LogMsg(const char *prefix, UdpMsg *msg); void LogEvent(const char *prefix, const UdpProtocol::Event &evt); void SendSyncRequest(); void SendMsg(UdpMsg *msg); - void PumpSendQueue(); void SendPendingOutput(); bool OnInvalid(UdpMsg *msg, int len); bool OnSyncRequest(UdpMsg *msg, int len); @@ -130,26 +125,16 @@ protected: bool OnQualityReport(UdpMsg *msg, int len); bool OnQualityReply(UdpMsg *msg, int len); bool OnKeepAlive(UdpMsg *msg, int len); - bool OnChat(UdpMsg *msg, int len); protected: /* * Network transmission information */ - Udp *_udp; - sockaddr_in _peer_addr; + ENetPeer *_peer; uint16 _magic_number; int _queue; uint16 _remote_magic_number; bool _connected; - int _send_latency; - int _oop_percent; - struct { - int send_time; - sockaddr_in dest_addr; - UdpMsg* msg; - } _oo_packet; - RingBuffer _send_queue; /* * Stats @@ -212,7 +197,6 @@ protected: * Event queue */ RingBuffer _event_queue; - std::vector _chatMessages; }; #endif diff --git a/dep/ggpo-x/src/poll.cpp b/dep/ggpo-x/src/poll.cpp deleted file mode 100644 index b5c0b5005..000000000 --- a/dep/ggpo-x/src/poll.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* ----------------------------------------------------------------------- - * GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC. - * - * Use of this software is governed by the MIT license that can be found - * in the LICENSE file. - */ - -#include "types.h" -#include "poll.h" - -Poll::Poll(void) : - _start_time(0) -{ -} - - -// -//void -//Poll::RegisterMsgLoop(IPollSink *sink, void *cookie) -//{ -// _msg_sinks.push_back(PollSinkCb(sink, cookie)); -//} - -void -Poll::RegisterLoop(IPollSink *sink, void *cookie) -{ - _loop_sinks.push_back(PollSinkCb(sink, cookie)); -} -//void -//Poll::RegisterPeriodic(IPollSink *sink, int interval, void *cookie) -//{ -// _periodic_sinks.push_back(PollPeriodicSinkCb(sink, cookie, interval)); -//} - -void -Poll::Run() -{ - while (Pump(100)) { - continue; - } -} - -bool -Poll::Pump(int timeout) -{ - int i; - bool finished = false; - - for (i = 0; i < _loop_sinks.size(); i++) { - PollSinkCb &cb = _loop_sinks[i]; - finished = !cb.sink->OnLoopPoll(cb.cookie) || finished; - } - return finished; -} -// -//int -//Poll::ComputeWaitTime(int elapsed) -//{ -// int waitTime = INFINITE; -// size_t count = _periodic_sinks.size(); -// -// if (count > 0) { -// for (int i = 0; i < count; i++) { -// PollPeriodicSinkCb &cb = _periodic_sinks[i]; -// int timeout = (cb.interval + cb.last_fired) - elapsed; -// if (waitTime == INFINITE || (timeout < waitTime)) { -// waitTime = MAX(timeout, 0); -// } -// } -// } -// return waitTime; -//} diff --git a/dep/ggpo-x/src/poll.h b/dep/ggpo-x/src/poll.h deleted file mode 100644 index 597cf58ba..000000000 --- a/dep/ggpo-x/src/poll.h +++ /dev/null @@ -1,56 +0,0 @@ -/* ----------------------------------------------------------------------- - * GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC. - * - * Use of this software is governed by the MIT license that can be found - * in the LICENSE file. - */ - -#ifndef _POLL_H -#define _POLL_H - -#include "static_buffer.h" - -#define MAX_POLLABLE_HANDLES 64 - - -class IPollSink { -public: - virtual ~IPollSink() { } - //virtual bool OnMsgPoll(void*) = 0;//{ return true; } - // virtual bool OnPeriodicPoll(void*, int) = 0;// { return true; } - virtual bool OnLoopPoll(void*) = 0;// { return true; } -}; - -class Poll { -public: - Poll(void); - void RegisterLoop(IPollSink *sink, void *cookie = NULL); - - void Run(); - bool Pump(int timeout); - -protected: - //int ComputeWaitTime(int elapsed); - - struct PollSinkCb { - IPollSink *sink; - void *cookie; - PollSinkCb() : sink(NULL), cookie(NULL) { } - PollSinkCb(IPollSink *s, void *c) : sink(s), cookie(c) { } - }; - - struct PollPeriodicSinkCb : public PollSinkCb { - int interval; - int last_fired; - PollPeriodicSinkCb() : PollSinkCb(NULL, NULL), interval(0), last_fired(0) { } - PollPeriodicSinkCb(IPollSink *s, void *c, int i) : - PollSinkCb(s, c), interval(i), last_fired(0) { } - }; - - int _start_time; - // StaticBuffer _msg_sinks; - StaticBuffer _loop_sinks; - // StaticBuffer _periodic_sinks; -}; - -#endif diff --git a/src/core/netplay.cpp b/src/core/netplay.cpp index f0641834e..0abf98b56 100644 --- a/src/core/netplay.cpp +++ b/src/core/netplay.cpp @@ -41,6 +41,7 @@ static bool NpBeginGameCb(void* ctx, const char* game_name); static void NpFreeBuffCb(void* ctx, void* buffer, int frame); static bool NpOnEventCb(void* ctx, GGPOEvent* ev); +static GGPOPlayerHandle PlayerIdToGGPOHandle(s32 player_id); static Input ReadLocalInput(); static GGPOErrorCode AddLocalInput(Netplay::Input input); static GGPOErrorCode SyncInput(Input inputs[2], int* disconnect_flags); @@ -58,6 +59,7 @@ static bool ConnectToLowerPeers(gsl::span peer_addresses); static bool WaitForPeerConnections(); static void HandleEnetEvent(const ENetEvent* event); static void PollEnet(Common::Timer::Value until_time); +static void HandleControlPacket(s32 player_id, const ENetPacket* pkt); // l = local, r = remote static s32 Start(s32 lhandle, u16 lport, const std::string& raddr, u16 rport, s32 ldelay, u32 pred, std::string game_path); @@ -154,6 +156,11 @@ void Netplay::ShutdownEnetHost() s_enet_host = nullptr; } +GGPOPlayerHandle PlayerIdToGGPOHandle(s32 player_id) +{ + return player_id + 1; +} + s32 Netplay::GetPlayerIdForPeer(const ENetPeer* peer) { for (s32 i = 0; i < MAX_PLAYERS; i++) @@ -213,6 +220,33 @@ void Netplay::HandleEnetEvent(const ENetEvent* event) } break; + case ENET_EVENT_TYPE_RECEIVE: + { + const s32 player_id = GetPlayerIdForPeer(event->peer); + if (player_id < 0) + { + Log_WarningPrintf("Received packet from unknown player"); + return; + } + + if (event->channelID == ENET_CHANNEL_CONTROL) + { + HandleControlPacket(player_id, event->packet); + } + else if (event->channelID == ENET_CHANNEL_GGPO) + { + Log_TracePrintf("Received %zu ggpo bytes from player %d", event->packet->dataLength, player_id); + const int rc = ggpo_handle_packet(s_ggpo, event->peer, event->packet); + if (rc != GGPO_OK) + Log_ErrorPrintf("Failed to process GGPO packet!"); + } + else + { + Log_ErrorPrintf("Unexpected packet channel %u", event->channelID); + } + } + break; + default: { Log_WarningPrintf("Unhandled enet event %d", event->type); @@ -307,6 +341,12 @@ bool Netplay::WaitForPeerConnections() return true; } +void Netplay::HandleControlPacket(s32 player_id, const ENetPacket* pkt) +{ + // TODO + Log_ErrorPrintf("Unhandled control packet from player %d of size %zu", player_id, pkt->dataLength); +} + s32 Netplay::Start(s32 lhandle, u16 lport, const std::string& raddr, u16 rport, s32 ldelay, u32 pred, std::string game_path) { SetSettings(); @@ -358,7 +398,7 @@ s32 Netplay::Start(s32 lhandle, u16 lport, const std::string& raddr, u16 rport, !ConnectToLowerPeers(gsl::span(peer_addresses).subspan(0, num_peer_addresses))) || !WaitForPeerConnections()) { - ShutdownEnetHost(); + // System shutdown cleans up enet. return -1; } @@ -377,37 +417,51 @@ s32 Netplay::Start(s32 lhandle, u16 lport, const std::string& raddr, u16 rport, GGPOErrorCode result; - result = - ggpo_start_session(&s_ggpo, &cb, "Duckstation-Netplay", 2, sizeof(Netplay::Input), lport, MAX_ROLLBACK_FRAMES); - // result = ggpo_start_synctest(&s_ggpo, &cb, (char*)"asdf", 2, sizeof(Netplay::Input), 1); + result = ggpo_start_session(&s_ggpo, &cb, "Duckstation-Netplay", MAX_PLAYERS, sizeof(Netplay::Input), lport, MAX_ROLLBACK_FRAMES); + if (!GGPO_SUCCEEDED(result)) + { + Log_ErrorPrintf("ggpo_start_session() failed: %d", result); + return -1; + } ggpo_set_disconnect_timeout(s_ggpo, 2000); ggpo_set_disconnect_notify_start(s_ggpo, 1000); - for (int i = 1; i <= 2; i++) + for (s32 i = 0; i < MAX_PLAYERS; i++) { - GGPOPlayer player = {}; - GGPOPlayerHandle handle = 0; + if (!s_enet_peers[i] && i != s_player_id) + continue; - player.size = sizeof(GGPOPlayer); - player.player_num = i; + // This is *awful*. Need to merge the player IDs, enough of this indices-start-at-1 rubbish. + const GGPOPlayerHandle expected_handle = PlayerIdToGGPOHandle(i); - if (lhandle == i) + GGPOPlayer player = { sizeof(GGPOPlayer) }; + GGPOPlayerHandle got_handle; + player.player_num = expected_handle; + if (i == s_player_id) { - player.type = GGPOPlayerType::GGPO_PLAYERTYPE_LOCAL; - result = ggpo_add_player(s_ggpo, &player, &handle); - s_local_handle = handle; + player.type = GGPO_PLAYERTYPE_LOCAL; + result = ggpo_add_player(s_ggpo, &player, &got_handle); + if (GGPO_SUCCEEDED(result)) + s_local_handle = got_handle; } else { - player.type = GGPOPlayerType::GGPO_PLAYERTYPE_REMOTE; - StringUtil::Strlcpy(player.u.remote.ip_address, raddr.c_str(), std::size(player.u.remote.ip_address)); - player.u.remote.port = rport; - result = ggpo_add_player(s_ggpo, &player, &handle); + player.type = GGPO_PLAYERTYPE_REMOTE; + player.u.remote.peer = s_enet_peers[i]; + result = ggpo_add_player(s_ggpo, &player, &got_handle); } + + if (!GGPO_SUCCEEDED(result)) + { + Log_ErrorPrintf("Failed to add player %d", i); + return -1; + } + + Assert(expected_handle == got_handle); } + ggpo_set_frame_delay(s_ggpo, s_local_handle, ldelay); - ggpo_set_manual_network_polling(s_ggpo, true); return result; } @@ -421,6 +475,8 @@ void Netplay::CloseSession() s_save_buffer_pool.clear(); s_local_handle = GGPO_INVALID_HANDLE; + ShutdownEnetHost(); + // Restore original settings. Host::Internal::SetNetplaySettingsLayer(nullptr); System::ApplySettings(false); @@ -527,9 +583,6 @@ void Netplay::Throttle() const Common::Timer::Value sleep_period = Common::Timer::ConvertMillisecondsToValue(1); for (;;) { - // Poll network. - ggpo_poll_network(s_ggpo); - // TODO: make better, we can tell this function to stall until the next frame PollEnet(0); @@ -630,6 +683,11 @@ void Netplay::CollectInput(u32 slot, u32 bind, float value) s_net_input[slot][bind] = value; } +GGPOPlayerHandle Netplay::PlayerIdToGGPOHandle(s32 player_id) +{ + return player_id + 1; +} + Netplay::Input Netplay::ReadLocalInput() { // get controller data of the first controller (0 internally) @@ -644,7 +702,6 @@ Netplay::Input Netplay::ReadLocalInput() void Netplay::SendMsg(const char* msg) { - ggpo_client_chat(s_ggpo, msg); } GGPOErrorCode Netplay::SyncInput(Netplay::Input inputs[2], int* disconnect_flags) @@ -830,9 +887,6 @@ bool Netplay::NpOnEventCb(void* ctx, GGPOEvent* ev) case GGPOEventCode::GGPO_EVENTCODE_CONNECTION_RESUMED: Host::OnNetplayMessage(fmt::format("Netplay Player: {} Connection Resumed", ev->u.connection_resumed.player)); break; - case GGPOEventCode::GGPO_EVENTCODE_CHAT: - Host::OnNetplayMessage(ev->u.chat.msg); - break; case GGPOEventCode::GGPO_EVENTCODE_TIMESYNC: HandleTimeSyncEvent(ev->u.timesync.frames_ahead, ev->u.timesync.timeSyncPeriodInFrames); break; diff --git a/src/core/netplay.h b/src/core/netplay.h index f2cb7419f..7456a748b 100644 --- a/src/core/netplay.h +++ b/src/core/netplay.h @@ -11,8 +11,14 @@ enum : s32 MAX_PLAYERS = 2, // Maximum netplay prediction frames MAX_ROLLBACK_FRAMES = 8, +}; - NUM_ENET_CHANNELS = 1, +enum : u8 +{ + ENET_CHANNEL_CONTROL = 0, + ENET_CHANNEL_GGPO = 1, + + NUM_ENET_CHANNELS, }; void StartNetplaySession(s32 local_handle, u16 local_port, std::string& remote_addr, u16 remote_port, s32 input_delay, diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp index 80b368fd1..9570a48a9 100644 --- a/src/duckstation-qt/qthost.cpp +++ b/src/duckstation-qt/qthost.cpp @@ -1089,6 +1089,9 @@ void EmuThread::startNetplaySession(int local_handle, quint16 local_port, const auto remAddr = remote_addr.trimmed().toStdString(); auto gamePath = game_path.trimmed().toStdString(); Netplay::StartNetplaySession(local_handle, local_port, remAddr, remote_port, input_delay, gamePath); + + // TODO: Fix this junk.. for some reason, it stays sleeping... + g_emu_thread->wakeThread(); } void EmuThread::sendNetplayMessage(const QString& message) @@ -2243,6 +2246,9 @@ int main(int argc, char* argv[]) std::string remote = "127.0.0.1"; std::string game = "D:\\PSX\\chd\\padtest.chd"; Netplay::StartNetplaySession(h, port_base + h, remote, port_base + nh, 1, game); + + // TODO: Fix this junk.. for some reason, it stays sleeping... + g_emu_thread->wakeThread(); }); }