Moved Traversal Client code over from old netplay
Moved over gui code for copying host code added gui to netplay diag setup to switch between direct and traversal connection
This commit is contained in:
parent
461a54338b
commit
4cdc307b87
|
@ -80,6 +80,8 @@
|
|||
<ClInclude Include="SysConf.h" />
|
||||
<ClInclude Include="Thread.h" />
|
||||
<ClInclude Include="Timer.h" />
|
||||
<ClInclude Include="TraversalClient.h" />
|
||||
<ClInclude Include="TraversalProto.h" />
|
||||
<ClInclude Include="x64ABI.h" />
|
||||
<ClInclude Include="x64Analyzer.h" />
|
||||
<ClInclude Include="x64Emitter.h" />
|
||||
|
@ -116,6 +118,7 @@
|
|||
<ClCompile Include="SysConf.cpp" />
|
||||
<ClCompile Include="Thread.cpp" />
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
<ClCompile Include="TraversalClient.cpp" />
|
||||
<ClCompile Include="Version.cpp" />
|
||||
<ClCompile Include="x64ABI.cpp" />
|
||||
<ClCompile Include="x64Analyzer.cpp" />
|
||||
|
@ -142,4 +145,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
|
@ -71,6 +71,9 @@
|
|||
</ClInclude>
|
||||
<ClInclude Include="GekkoDisassembler.h" />
|
||||
<ClInclude Include="Event.h" />
|
||||
<ClInclude Include="JitRegister.h" />
|
||||
<ClInclude Include="TraversalClient.h" />
|
||||
<ClInclude Include="TraversalProto.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BreakPoints.cpp" />
|
||||
|
@ -117,8 +120,10 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="XSaveWorkaround.cpp" />
|
||||
<ClCompile Include="GekkoDisassembler.cpp" />
|
||||
<ClCompile Include="JitRegister.cpp" />
|
||||
<ClCompile Include="TraversalClient.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
|
@ -0,0 +1,370 @@
|
|||
// This file is public domain, in case it's useful to anyone. -comex
|
||||
|
||||
#include "Common/TraversalClient.h"
|
||||
#include "enet/enet.h"
|
||||
#include "Timer.h"
|
||||
|
||||
static void GetRandomishBytes(u8* buf, size_t size)
|
||||
{
|
||||
// We don't need high quality random numbers (which might not be available),
|
||||
// just non-repeating numbers!
|
||||
srand(enet_time_get());
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buf[i] = rand() & 0xff;
|
||||
}
|
||||
|
||||
TraversalClient::TraversalClient(ENetHost* netHost, const std::string& server)
|
||||
: m_NetHost(netHost)
|
||||
, m_Server(server)
|
||||
, m_Client(nullptr)
|
||||
, m_FailureReason(0)
|
||||
, m_ConnectRequestId(0)
|
||||
, m_PendingConnect(false)
|
||||
, m_PingTime(0)
|
||||
{
|
||||
netHost->intercept = TraversalClient::InterceptCallback;
|
||||
|
||||
Reset();
|
||||
|
||||
ReconnectToServer();
|
||||
}
|
||||
|
||||
TraversalClient::~TraversalClient()
|
||||
{
|
||||
}
|
||||
|
||||
void TraversalClient::ReconnectToServer()
|
||||
{
|
||||
m_Server = "vps.qoid.us"; // XXX
|
||||
if (enet_address_set_host(&m_ServerAddress, m_Server.c_str()))
|
||||
{
|
||||
OnFailure(BadHost);
|
||||
return;
|
||||
}
|
||||
m_ServerAddress.port = 6262;
|
||||
|
||||
m_State = Connecting;
|
||||
|
||||
TraversalPacket hello = {};
|
||||
hello.type = TraversalPacketHelloFromClient;
|
||||
hello.helloFromClient.protoVersion = TraversalProtoVersion;
|
||||
SendTraversalPacket(hello);
|
||||
if (m_Client)
|
||||
m_Client->OnTraversalStateChanged();
|
||||
}
|
||||
|
||||
static ENetAddress MakeENetAddress(TraversalInetAddress* address)
|
||||
{
|
||||
ENetAddress eaddr;
|
||||
if (address->isIPV6)
|
||||
{
|
||||
eaddr.port = 0; // no support yet :(
|
||||
}
|
||||
else
|
||||
{
|
||||
eaddr.host = address->address[0];
|
||||
eaddr.port = ntohs(address->port);
|
||||
}
|
||||
return eaddr;
|
||||
}
|
||||
|
||||
void TraversalClient::ConnectToClient(const std::string& host)
|
||||
{
|
||||
if (host.size() > sizeof(TraversalHostId))
|
||||
{
|
||||
PanicAlert("host too long");
|
||||
return;
|
||||
}
|
||||
TraversalPacket packet = {};
|
||||
packet.type = TraversalPacketConnectPlease;
|
||||
memcpy(packet.connectPlease.hostId.data(), host.c_str(), host.size());
|
||||
m_ConnectRequestId = SendTraversalPacket(packet);
|
||||
m_PendingConnect = true;
|
||||
}
|
||||
|
||||
bool TraversalClient::TestPacket(u8* data, size_t size, ENetAddress* from)
|
||||
{
|
||||
if (from->host == m_ServerAddress.host &&
|
||||
from->port == m_ServerAddress.port)
|
||||
{
|
||||
if (size < sizeof(TraversalPacket))
|
||||
{
|
||||
ERROR_LOG(NETPLAY, "Received too-short traversal packet.");
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleServerPacket((TraversalPacket*) data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--Temporary until more of the old netplay branch is moved over
|
||||
void TraversalClient::Update()
|
||||
{
|
||||
ENetEvent netEvent;
|
||||
if (enet_host_service(m_NetHost, &netEvent, 4) > 0)
|
||||
{
|
||||
switch (netEvent.type)
|
||||
{
|
||||
case ENET_EVENT_TYPE_RECEIVE:
|
||||
TestPacket(netEvent.packet->data, netEvent.packet->dataLength, &netEvent.peer->address);
|
||||
|
||||
enet_packet_destroy(netEvent.packet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
HandleResends();
|
||||
}
|
||||
|
||||
void TraversalClient::HandleServerPacket(TraversalPacket* packet)
|
||||
{
|
||||
u8 ok = 1;
|
||||
switch (packet->type)
|
||||
{
|
||||
case TraversalPacketAck:
|
||||
if (!packet->ack.ok)
|
||||
{
|
||||
OnFailure(ServerForgotAboutUs);
|
||||
break;
|
||||
}
|
||||
for (auto it = m_OutgoingTraversalPackets.begin(); it != m_OutgoingTraversalPackets.end(); ++it)
|
||||
{
|
||||
if (it->packet.requestId == packet->requestId)
|
||||
{
|
||||
m_OutgoingTraversalPackets.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TraversalPacketHelloFromServer:
|
||||
if (m_State != Connecting)
|
||||
break;
|
||||
if (!packet->helloFromServer.ok)
|
||||
{
|
||||
OnFailure(VersionTooOld);
|
||||
break;
|
||||
}
|
||||
m_HostId = packet->helloFromServer.yourHostId;
|
||||
m_State = Connected;
|
||||
if (m_Client)
|
||||
m_Client->OnTraversalStateChanged();
|
||||
break;
|
||||
case TraversalPacketPleaseSendPacket:
|
||||
{
|
||||
// security is overrated.
|
||||
ENetAddress addr = MakeENetAddress(&packet->pleaseSendPacket.address);
|
||||
if (addr.port != 0)
|
||||
{
|
||||
char message[] = "Hello from Dolphin Netplay...";
|
||||
ENetBuffer buf;
|
||||
buf.data = message;
|
||||
buf.dataLength = sizeof(message) - 1;
|
||||
enet_socket_send(m_NetHost->socket, &addr, &buf, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// invalid IPV6
|
||||
ok = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TraversalPacketConnectReady:
|
||||
case TraversalPacketConnectFailed:
|
||||
{
|
||||
if (!m_PendingConnect || packet->connectReady.requestId != m_ConnectRequestId)
|
||||
break;
|
||||
|
||||
m_PendingConnect = false;
|
||||
|
||||
if (!m_Client)
|
||||
break;
|
||||
|
||||
if (packet->type == TraversalPacketConnectReady)
|
||||
m_Client->OnConnectReady(MakeENetAddress(&packet->connectReady.address));
|
||||
else
|
||||
m_Client->OnConnectFailed(packet->connectFailed.reason);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WARN_LOG(NETPLAY, "Received unknown packet with type %d", packet->type);
|
||||
break;
|
||||
}
|
||||
if (packet->type != TraversalPacketAck)
|
||||
{
|
||||
TraversalPacket ack = {};
|
||||
ack.type = TraversalPacketAck;
|
||||
ack.requestId = packet->requestId;
|
||||
ack.ack.ok = ok;
|
||||
|
||||
ENetBuffer buf;
|
||||
buf.data = &ack;
|
||||
buf.dataLength = sizeof(ack);
|
||||
if (enet_socket_send(m_NetHost->socket, &m_ServerAddress, &buf, 1) == -1)
|
||||
OnFailure(SocketSendError);
|
||||
}
|
||||
}
|
||||
|
||||
void TraversalClient::OnFailure(int reason)
|
||||
{
|
||||
m_State = Failure;
|
||||
m_FailureReason = reason;
|
||||
|
||||
switch (reason)
|
||||
{
|
||||
case TraversalClient::BadHost:
|
||||
{
|
||||
auto server = "dolphin-emu.org";
|
||||
PanicAlertT("Couldn't look up central server %s", server);
|
||||
break;
|
||||
}
|
||||
case TraversalClient::VersionTooOld:
|
||||
PanicAlertT("Dolphin too old for traversal server");
|
||||
break;
|
||||
case TraversalClient::ServerForgotAboutUs:
|
||||
PanicAlertT("Disconnected from traversal server");
|
||||
break;
|
||||
case TraversalClient::SocketSendError:
|
||||
PanicAlertT("Socket error sending to traversal server");
|
||||
break;
|
||||
case TraversalClient::ResendTimeout:
|
||||
PanicAlertT("Timeout connecting to traversal server");
|
||||
break;
|
||||
default:
|
||||
PanicAlertT("Unknown error %x", reason);
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_Client)
|
||||
m_Client->OnTraversalStateChanged();
|
||||
}
|
||||
|
||||
void TraversalClient::ResendPacket(OutgoingTraversalPacketInfo* info)
|
||||
{
|
||||
info->sendTime = enet_time_get();
|
||||
info->tries++;
|
||||
ENetBuffer buf;
|
||||
buf.data = &info->packet;
|
||||
buf.dataLength = sizeof(info->packet);
|
||||
if (enet_socket_send(m_NetHost->socket, &m_ServerAddress, &buf, 1) == -1)
|
||||
OnFailure(SocketSendError);
|
||||
}
|
||||
|
||||
void TraversalClient::HandleResends()
|
||||
{
|
||||
enet_uint32 now = enet_time_get();
|
||||
for (auto& tpi : m_OutgoingTraversalPackets)
|
||||
{
|
||||
if (now - tpi.sendTime >= (u32) (300 * tpi.tries))
|
||||
{
|
||||
if (tpi.tries >= 5)
|
||||
{
|
||||
OnFailure(ResendTimeout);
|
||||
m_OutgoingTraversalPackets.clear();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
ResendPacket(&tpi);
|
||||
}
|
||||
}
|
||||
}
|
||||
HandlePing();
|
||||
}
|
||||
|
||||
void TraversalClient::HandlePing()
|
||||
{
|
||||
enet_uint32 now = enet_time_get();
|
||||
if (m_State == Connected && now - m_PingTime >= 500)
|
||||
{
|
||||
TraversalPacket ping = {0};
|
||||
ping.type = TraversalPacketPing;
|
||||
ping.ping.hostId = m_HostId;
|
||||
SendTraversalPacket(ping);
|
||||
m_PingTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
TraversalRequestId TraversalClient::SendTraversalPacket(const TraversalPacket& packet)
|
||||
{
|
||||
OutgoingTraversalPacketInfo info;
|
||||
info.packet = packet;
|
||||
GetRandomishBytes((u8*) &info.packet.requestId, sizeof(info.packet.requestId));
|
||||
info.tries = 0;
|
||||
m_OutgoingTraversalPackets.push_back(info);
|
||||
ResendPacket(&m_OutgoingTraversalPackets.back());
|
||||
return info.packet.requestId;
|
||||
}
|
||||
|
||||
void TraversalClient::Reset()
|
||||
{
|
||||
m_PendingConnect = false;
|
||||
m_Client = nullptr;
|
||||
}
|
||||
|
||||
int ENET_CALLBACK TraversalClient::InterceptCallback(ENetHost* host, ENetEvent* event)
|
||||
{
|
||||
auto traversalClient = g_TraversalClient.get();
|
||||
if (traversalClient->TestPacket(host->receivedData, host->receivedDataLength, &host->receivedAddress))
|
||||
{
|
||||
event->type = (ENetEventType)42;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<TraversalClient> g_TraversalClient;
|
||||
std::unique_ptr<ENetHost> g_MainNetHost;
|
||||
|
||||
// The settings at the previous TraversalClient reset - notably, we
|
||||
// need to know not just what port it's on, but whether it was
|
||||
// explicitly requested.
|
||||
static std::string g_OldServer;
|
||||
static u16 g_OldPort;
|
||||
|
||||
bool EnsureTraversalClient(const std::string& server, u16 port)
|
||||
{
|
||||
if (!g_MainNetHost || !g_TraversalClient || server != g_OldServer || port != g_OldPort)
|
||||
{
|
||||
g_OldServer = server;
|
||||
g_OldPort = port;
|
||||
|
||||
ENetAddress addr = { ENET_HOST_ANY, port };
|
||||
ENetHost* host = enet_host_create(
|
||||
&addr, // address
|
||||
50, // peerCount
|
||||
1, // channelLimit
|
||||
0, // incomingBandwidth
|
||||
0); // outgoingBandwidth
|
||||
if (!host)
|
||||
{
|
||||
g_MainNetHost.reset();
|
||||
return false;
|
||||
}
|
||||
g_MainNetHost.reset(host);
|
||||
|
||||
g_TraversalClient.reset(new TraversalClient(g_MainNetHost.get(), server));
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReleaseTraversalClient()
|
||||
{
|
||||
if (!g_TraversalClient)
|
||||
return;
|
||||
|
||||
if (g_OldPort != 0)
|
||||
{
|
||||
// If we were listening at a specific port, kill the
|
||||
// TraversalClient to avoid hanging on to the port.
|
||||
g_TraversalClient.reset();
|
||||
g_MainNetHost.reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reset any pending connection attempts.
|
||||
g_TraversalClient->Reset();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
// This file is public domain, in case it's useful to anyone. -comex
|
||||
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include "Common/Common.h"
|
||||
#include "Common/Thread.h"
|
||||
#include "Common/TraversalProto.h"
|
||||
|
||||
#include "enet/enet.h"
|
||||
|
||||
class TraversalClientClient
|
||||
{
|
||||
public:
|
||||
virtual ~TraversalClientClient(){};
|
||||
virtual void OnTraversalStateChanged()=0;
|
||||
virtual void OnConnectReady(ENetAddress addr)=0;
|
||||
virtual void OnConnectFailed(u8 reason)=0;
|
||||
};
|
||||
|
||||
class TraversalClient
|
||||
{
|
||||
public:
|
||||
enum State
|
||||
{
|
||||
Connecting,
|
||||
Connected,
|
||||
Failure
|
||||
};
|
||||
|
||||
enum FailureReason
|
||||
{
|
||||
BadHost = 0x300,
|
||||
VersionTooOld,
|
||||
ServerForgotAboutUs,
|
||||
SocketSendError,
|
||||
ResendTimeout,
|
||||
ConnectFailedError = 0x400,
|
||||
};
|
||||
|
||||
TraversalClient(ENetHost* netHost, const std::string& server);
|
||||
~TraversalClient();
|
||||
void Reset();
|
||||
void ConnectToClient(const std::string& host);
|
||||
void ReconnectToServer();
|
||||
void Update();
|
||||
|
||||
// called from NetHost
|
||||
bool TestPacket(u8* data, size_t size, ENetAddress* from);
|
||||
void HandleResends();
|
||||
|
||||
ENetHost* m_NetHost;
|
||||
TraversalClientClient* m_Client;
|
||||
TraversalHostId m_HostId;
|
||||
State m_State;
|
||||
int m_FailureReason;
|
||||
|
||||
private:
|
||||
struct OutgoingTraversalPacketInfo
|
||||
{
|
||||
TraversalPacket packet;
|
||||
int tries;
|
||||
enet_uint32 sendTime;
|
||||
};
|
||||
|
||||
void HandleServerPacket(TraversalPacket* packet);
|
||||
void ResendPacket(OutgoingTraversalPacketInfo* info);
|
||||
TraversalRequestId SendTraversalPacket(const TraversalPacket& packet);
|
||||
void OnFailure(int reason);
|
||||
void HandlePing();
|
||||
static int ENET_CALLBACK InterceptCallback(ENetHost* host, ENetEvent* event);
|
||||
|
||||
TraversalRequestId m_ConnectRequestId;
|
||||
bool m_PendingConnect;
|
||||
std::list<OutgoingTraversalPacketInfo> m_OutgoingTraversalPackets;
|
||||
ENetAddress m_ServerAddress;
|
||||
std::string m_Server;
|
||||
enet_uint32 m_PingTime;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<TraversalClient> g_TraversalClient;
|
||||
// the NetHost connected to the TraversalClient.
|
||||
extern std::unique_ptr<ENetHost> g_MainNetHost;
|
||||
|
||||
// Create g_TraversalClient and g_MainNetHost if necessary.
|
||||
bool EnsureTraversalClient(const std::string& server, u16 port);
|
||||
void ReleaseTraversalClient();
|
|
@ -0,0 +1,96 @@
|
|||
// This file is public domain, in case it's useful to anyone. -comex
|
||||
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
|
||||
typedef std::array<char, 8> TraversalHostId;
|
||||
typedef u64 TraversalRequestId;
|
||||
|
||||
enum TraversalPacketType
|
||||
{
|
||||
// [*->*]
|
||||
TraversalPacketAck = 0,
|
||||
// [c->s]
|
||||
TraversalPacketPing = 1,
|
||||
// [c->s]
|
||||
TraversalPacketHelloFromClient = 2,
|
||||
// [s->c]
|
||||
TraversalPacketHelloFromServer = 3,
|
||||
// [c->s] When connecting, first the client asks the central server...
|
||||
TraversalPacketConnectPlease = 4,
|
||||
// [s->c] ...who asks the game host to send a UDP packet to the
|
||||
// client... (an ack implies success)
|
||||
TraversalPacketPleaseSendPacket = 5,
|
||||
// [s->c] ...which the central server relays back to the client.
|
||||
TraversalPacketConnectReady = 6,
|
||||
// [s->c] Alternately, the server might not have heard of this host.
|
||||
TraversalPacketConnectFailed = 7
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TraversalProtoVersion = 0
|
||||
};
|
||||
|
||||
enum TraversalConnectFailedReason
|
||||
{
|
||||
TraversalConnectFailedClientDidntRespond = 0,
|
||||
TraversalConnectFailedClientFailure,
|
||||
TraversalConnectFailedNoSuchClient
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct TraversalInetAddress
|
||||
{
|
||||
u8 isIPV6;
|
||||
u32 address[4];
|
||||
u16 port;
|
||||
};
|
||||
struct TraversalPacket
|
||||
{
|
||||
u8 type;
|
||||
TraversalRequestId requestId;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u8 ok;
|
||||
} ack;
|
||||
struct
|
||||
{
|
||||
TraversalHostId hostId;
|
||||
} ping;
|
||||
struct
|
||||
{
|
||||
u8 protoVersion;
|
||||
} helloFromClient;
|
||||
struct
|
||||
{
|
||||
u8 ok;
|
||||
TraversalHostId yourHostId;
|
||||
TraversalInetAddress yourAddress; // currently unused
|
||||
} helloFromServer;
|
||||
struct
|
||||
{
|
||||
TraversalHostId hostId;
|
||||
} connectPlease;
|
||||
struct
|
||||
{
|
||||
TraversalInetAddress address;
|
||||
} pleaseSendPacket;
|
||||
struct
|
||||
{
|
||||
TraversalRequestId requestId;
|
||||
TraversalInetAddress address;
|
||||
} connectReady;
|
||||
struct
|
||||
{
|
||||
TraversalRequestId requestId;
|
||||
u8 reason;
|
||||
} connectFailed;
|
||||
};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
|
@ -38,10 +38,25 @@ NetPlayClient::~NetPlayClient()
|
|||
Disconnect();
|
||||
}
|
||||
|
||||
if (g_MainNetHost.get() == m_client)
|
||||
{
|
||||
g_MainNetHost.release();
|
||||
}
|
||||
if (m_client)
|
||||
{
|
||||
enet_host_destroy(m_client);
|
||||
m_client = nullptr;
|
||||
}
|
||||
|
||||
if (m_traversal_client)
|
||||
{
|
||||
ReleaseTraversalClient();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// called from ---GUI--- thread
|
||||
NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name)
|
||||
NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name, bool traversal)
|
||||
: m_dialog(dialog)
|
||||
, m_client(nullptr)
|
||||
, m_server(nullptr)
|
||||
|
@ -53,6 +68,8 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay
|
|||
, m_is_recording(false)
|
||||
, m_pid(0)
|
||||
, m_connecting(false)
|
||||
, m_traversal_client(nullptr)
|
||||
, m_state(Failure)
|
||||
{
|
||||
m_target_buffer_size = 20;
|
||||
ClearBuffers();
|
||||
|
@ -61,35 +78,81 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay
|
|||
|
||||
m_player_name = name;
|
||||
|
||||
//Direct Connection
|
||||
m_client = enet_host_create(nullptr, 1, 3, 0, 0);
|
||||
|
||||
if (m_client == nullptr)
|
||||
if (!traversal)
|
||||
{
|
||||
PanicAlertT("Couldn't Create Client");
|
||||
}
|
||||
//Direct Connection
|
||||
m_client = enet_host_create(nullptr, 1, 3, 0, 0);
|
||||
|
||||
ENetAddress addr;
|
||||
enet_address_set_host(&addr, address.c_str());
|
||||
addr.port = port;
|
||||
if (m_client == nullptr)
|
||||
{
|
||||
PanicAlertT("Couldn't Create Client");
|
||||
}
|
||||
|
||||
m_server = enet_host_connect(m_client, &addr, 3, 0);
|
||||
ENetAddress addr;
|
||||
enet_address_set_host(&addr, address.c_str());
|
||||
addr.port = port;
|
||||
|
||||
if (m_server == nullptr)
|
||||
{
|
||||
PanicAlertT("Couldn't create peer.");
|
||||
}
|
||||
m_server = enet_host_connect(m_client, &addr, 3, 0);
|
||||
|
||||
if (m_server == nullptr)
|
||||
{
|
||||
PanicAlertT("Couldn't create peer.");
|
||||
}
|
||||
|
||||
ENetEvent netEvent;
|
||||
int net = enet_host_service(m_client, &netEvent, 5000);
|
||||
if (net > 0 && netEvent.type == ENET_EVENT_TYPE_CONNECT)
|
||||
{
|
||||
if (Connect())
|
||||
m_thread = std::thread(&NetPlayClient::ThreadFunc, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlertT("Failed to Connect!");
|
||||
}
|
||||
|
||||
ENetEvent netEvent;
|
||||
int net = enet_host_service(m_client, &netEvent, 5000);
|
||||
if (net > 0 && netEvent.type == ENET_EVENT_TYPE_CONNECT)
|
||||
{
|
||||
if (Connect())
|
||||
m_thread = std::thread(&NetPlayClient::ThreadFunc, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlertT("Failed to Connect!");
|
||||
//Traversal Server
|
||||
if (!EnsureTraversalClient("dolphin-emu.org", 0))
|
||||
return;
|
||||
m_client = g_MainNetHost.get();
|
||||
|
||||
m_traversal_client = g_TraversalClient.get();
|
||||
|
||||
// If we were disconnected in the background, reconnect.
|
||||
if (m_traversal_client->m_State == TraversalClient::Failure)
|
||||
m_traversal_client->ReconnectToServer();
|
||||
m_traversal_client->m_Client = this;
|
||||
m_host_spec = address;
|
||||
m_state = WaitingForTraversalClientConnection;
|
||||
OnTraversalStateChanged();
|
||||
m_connecting = true;
|
||||
|
||||
while (m_connecting)
|
||||
{
|
||||
ENetEvent netEvent;
|
||||
if (m_traversal_client)
|
||||
m_traversal_client->HandleResends();
|
||||
|
||||
while (enet_host_service(m_client, &netEvent, 4) > 0)
|
||||
{
|
||||
sf::Packet rpac;
|
||||
switch (netEvent.type)
|
||||
{
|
||||
case ENET_EVENT_TYPE_CONNECT:
|
||||
m_server = netEvent.peer;
|
||||
if (Connect())
|
||||
{
|
||||
m_state = Connected;
|
||||
m_thread = std::thread(&NetPlayClient::ThreadFunc, this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
PanicAlertT("Failed To Connect!");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,6 +443,7 @@ void NetPlayClient::Send(sf::Packet& packet)
|
|||
void NetPlayClient::Disconnect()
|
||||
{
|
||||
ENetEvent netEvent;
|
||||
m_state = Failure;
|
||||
enet_peer_disconnect(m_server, 0);
|
||||
while (enet_host_service(m_client, &netEvent, 3000) > 0)
|
||||
{
|
||||
|
@ -407,6 +471,8 @@ void NetPlayClient::ThreadFunc()
|
|||
int net;
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
||||
if (m_traversal_client)
|
||||
m_traversal_client->HandleResends();
|
||||
net = enet_host_service(m_client, &netEvent, 4);
|
||||
}
|
||||
if (net > 0)
|
||||
|
@ -630,6 +696,55 @@ void NetPlayClient::ClearBuffers()
|
|||
}
|
||||
}
|
||||
|
||||
// called from ---NETPLAY--- thread
|
||||
void NetPlayClient::OnTraversalStateChanged()
|
||||
{
|
||||
if (m_state == WaitingForTraversalClientConnection &&
|
||||
m_traversal_client->m_State == TraversalClient::Connected)
|
||||
{
|
||||
m_state = WaitingForTraversalClientConnectReady;
|
||||
m_traversal_client->ConnectToClient(m_host_spec);
|
||||
}
|
||||
else if (m_state != Failure &&
|
||||
m_traversal_client->m_State == TraversalClient::Failure)
|
||||
{
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
// called from ---NETPLAY--- thread
|
||||
void NetPlayClient::OnConnectReady(ENetAddress addr)
|
||||
{
|
||||
if (m_state == WaitingForTraversalClientConnectReady)
|
||||
{
|
||||
m_state = Connecting;
|
||||
enet_host_connect(m_client, &addr, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// called from ---NETPLAY--- thread
|
||||
void NetPlayClient::OnConnectFailed(u8 reason)
|
||||
{
|
||||
m_connecting = false;
|
||||
m_state = Failure;
|
||||
int swtch = TraversalClient::ConnectFailedError + reason;
|
||||
switch (swtch)
|
||||
{
|
||||
case TraversalClient::ConnectFailedError + TraversalConnectFailedClientDidntRespond:
|
||||
PanicAlertT("Traversal server timed out connecting to the host");
|
||||
break;
|
||||
case TraversalClient::ConnectFailedError + TraversalConnectFailedClientFailure:
|
||||
PanicAlertT("Server rejected traversal attempt");
|
||||
break;
|
||||
case TraversalClient::ConnectFailedError + TraversalConnectFailedNoSuchClient:
|
||||
PanicAlertT("Invalid host");
|
||||
break;
|
||||
default:
|
||||
PanicAlertT("Unknown error %x", swtch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// called from ---CPU--- thread
|
||||
bool NetPlayClient::GetNetPads(const u8 pad_nb, GCPadStatus* pad_status)
|
||||
{
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
#include <map>
|
||||
#include <queue>
|
||||
#include <sstream>
|
||||
|
||||
#include "enet/enet.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FifoQueue.h"
|
||||
#include "Common/Thread.h"
|
||||
#include "Common/Timer.h"
|
||||
#include "Common/TraversalClient.h"
|
||||
#include "Core/NetPlayProto.h"
|
||||
#include "InputCommon/GCPadStatus.h"
|
||||
#include <SFML/Network/Packet.hpp>
|
||||
|
@ -43,12 +42,12 @@ public:
|
|||
u32 ping;
|
||||
};
|
||||
|
||||
class NetPlayClient
|
||||
class NetPlayClient : public TraversalClientClient
|
||||
{
|
||||
public:
|
||||
void ThreadFunc();
|
||||
|
||||
NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name);
|
||||
NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name, bool traversal);
|
||||
~NetPlayClient();
|
||||
|
||||
void GetPlayerList(std::string& list, std::vector<int>& pid_list);
|
||||
|
@ -66,11 +65,25 @@ public:
|
|||
bool WiimoteUpdate(int _number, u8* data, const u8 size);
|
||||
bool GetNetPads(const u8 pad_nb, GCPadStatus* pad_status);
|
||||
|
||||
void OnTraversalStateChanged() override;
|
||||
void OnConnectReady(ENetAddress addr) override;
|
||||
void OnConnectFailed(u8 reason) override;
|
||||
|
||||
u8 LocalPadToInGamePad(u8 localPad);
|
||||
u8 InGamePadToLocalPad(u8 localPad);
|
||||
|
||||
u8 LocalWiimoteToInGameWiimote(u8 local_pad);
|
||||
|
||||
enum State
|
||||
{
|
||||
WaitingForTraversalClientConnection,
|
||||
WaitingForTraversalClientConnectReady,
|
||||
Connecting,
|
||||
WaitingForHelloResponse,
|
||||
Connected,
|
||||
Failure
|
||||
} m_state;
|
||||
|
||||
protected:
|
||||
void ClearBuffers();
|
||||
|
||||
|
@ -121,6 +134,7 @@ private:
|
|||
std::string m_host_spec;
|
||||
std::string m_player_name;
|
||||
bool m_connecting;
|
||||
TraversalClient* m_traversal_client;
|
||||
};
|
||||
|
||||
void NetPlay_Enable(NetPlayClient* const np);
|
||||
|
|
|
@ -34,32 +34,31 @@ typedef std::vector<u8> NetWiimote;
|
|||
|
||||
static const int NETPLAY_INITIAL_GCTIME = 1272737767;
|
||||
|
||||
|
||||
// messages
|
||||
enum
|
||||
{
|
||||
NP_MSG_PLAYER_JOIN = 0x10,
|
||||
NP_MSG_PLAYER_LEAVE = 0x11,
|
||||
NP_MSG_PLAYER_JOIN = 0x10,
|
||||
NP_MSG_PLAYER_LEAVE = 0x11,
|
||||
|
||||
NP_MSG_CHAT_MESSAGE = 0x30,
|
||||
NP_MSG_CHAT_MESSAGE = 0x30,
|
||||
|
||||
NP_MSG_PAD_DATA = 0x60,
|
||||
NP_MSG_PAD_MAPPING = 0x61,
|
||||
NP_MSG_PAD_BUFFER = 0x62,
|
||||
NP_MSG_PAD_DATA = 0x60,
|
||||
NP_MSG_PAD_MAPPING = 0x61,
|
||||
NP_MSG_PAD_BUFFER = 0x62,
|
||||
|
||||
NP_MSG_WIIMOTE_DATA = 0x70,
|
||||
NP_MSG_WIIMOTE_MAPPING = 0x71,
|
||||
NP_MSG_WIIMOTE_DATA = 0x70,
|
||||
NP_MSG_WIIMOTE_MAPPING = 0x71,
|
||||
|
||||
NP_MSG_START_GAME = 0xA0,
|
||||
NP_MSG_CHANGE_GAME = 0xA1,
|
||||
NP_MSG_STOP_GAME = 0xA2,
|
||||
NP_MSG_DISABLE_GAME = 0xA3,
|
||||
NP_MSG_START_GAME = 0xA0,
|
||||
NP_MSG_CHANGE_GAME = 0xA1,
|
||||
NP_MSG_STOP_GAME = 0xA2,
|
||||
NP_MSG_DISABLE_GAME = 0xA3,
|
||||
|
||||
NP_MSG_READY = 0xD0,
|
||||
NP_MSG_NOT_READY = 0xD1,
|
||||
NP_MSG_READY = 0xD0,
|
||||
NP_MSG_NOT_READY = 0xD1,
|
||||
|
||||
NP_MSG_PING = 0xE0,
|
||||
NP_MSG_PONG = 0xE1,
|
||||
NP_MSG_PING = 0xE0,
|
||||
NP_MSG_PONG = 0xE1,
|
||||
NP_MSG_PLAYER_PING_DATA = 0xE2,
|
||||
};
|
||||
|
||||
|
@ -70,8 +69,8 @@ typedef u32 FrameNum;
|
|||
|
||||
enum
|
||||
{
|
||||
CON_ERR_SERVER_FULL = 1,
|
||||
CON_ERR_GAME_RUNNING = 2,
|
||||
CON_ERR_SERVER_FULL = 1,
|
||||
CON_ERR_GAME_RUNNING = 2,
|
||||
CON_ERR_VERSION_MISMATCH = 3
|
||||
};
|
||||
|
||||
|
|
|
@ -19,6 +19,17 @@ NetPlayServer::~NetPlayServer()
|
|||
m_do_loop = false;
|
||||
m_thread.join();
|
||||
enet_host_destroy(m_server);
|
||||
|
||||
if (g_MainNetHost.get() == m_server)
|
||||
{
|
||||
g_MainNetHost.release();
|
||||
}
|
||||
|
||||
if (m_traversal_client)
|
||||
{
|
||||
g_TraversalClient->m_Client = nullptr;
|
||||
ReleaseTraversalClient();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_UPNP
|
||||
|
@ -30,7 +41,7 @@ NetPlayServer::~NetPlayServer()
|
|||
}
|
||||
|
||||
// called from ---GUI--- thread
|
||||
NetPlayServer::NetPlayServer(const u16 port)
|
||||
NetPlayServer::NetPlayServer(const u16 port, bool traversal)
|
||||
: is_connected(false)
|
||||
, m_is_running(false)
|
||||
, m_do_loop(false)
|
||||
|
@ -40,6 +51,8 @@ NetPlayServer::NetPlayServer(const u16 port)
|
|||
, m_target_buffer_size(0)
|
||||
, m_selected_game("")
|
||||
, m_server(nullptr)
|
||||
, m_traversal_client(nullptr)
|
||||
, m_dialog(nullptr)
|
||||
{
|
||||
//--use server time
|
||||
if (enet_initialize() != 0)
|
||||
|
@ -49,11 +62,26 @@ NetPlayServer::NetPlayServer(const u16 port)
|
|||
|
||||
memset(m_pad_map, -1, sizeof(m_pad_map));
|
||||
memset(m_wiimote_map, -1, sizeof(m_wiimote_map));
|
||||
|
||||
ENetAddress serverAddr;
|
||||
serverAddr.host = ENET_HOST_ANY;
|
||||
serverAddr.port = port;
|
||||
m_server = enet_host_create(&serverAddr, 10, 3, 0, 0);
|
||||
if (traversal)
|
||||
{
|
||||
if (!EnsureTraversalClient("dolphin-emu.org", 0))
|
||||
return;
|
||||
|
||||
g_TraversalClient->m_Client = this;
|
||||
m_traversal_client = g_TraversalClient.get();
|
||||
|
||||
m_server = g_MainNetHost.get();
|
||||
|
||||
if (g_TraversalClient->m_State == TraversalClient::Failure)
|
||||
g_TraversalClient->ReconnectToServer();
|
||||
}
|
||||
else
|
||||
{
|
||||
ENetAddress serverAddr;
|
||||
serverAddr.host = ENET_HOST_ANY;
|
||||
serverAddr.port = port;
|
||||
m_server = enet_host_create(&serverAddr, 10, 3, 0, 0);
|
||||
}
|
||||
|
||||
if (m_server != nullptr)
|
||||
{
|
||||
|
@ -89,6 +117,8 @@ void NetPlayServer::ThreadFunc()
|
|||
int net;
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
||||
if (m_traversal_client)
|
||||
m_traversal_client->HandleResends();
|
||||
net = enet_host_service(m_server, &netEvent, 4);
|
||||
}
|
||||
if (net > 0)
|
||||
|
@ -533,6 +563,13 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void NetPlayServer::OnTraversalStateChanged()
|
||||
{
|
||||
if (m_dialog)
|
||||
m_dialog->Update();
|
||||
}
|
||||
|
||||
// called from ---GUI--- thread / and ---NETPLAY--- thread
|
||||
void NetPlayServer::SendChatMessage(const std::string& msg)
|
||||
{
|
||||
|
@ -638,6 +675,96 @@ u16 NetPlayServer::GetPort()
|
|||
return m_server->address.port;
|
||||
}
|
||||
|
||||
void NetPlayServer::SetNetPlayUI(NetPlayUI* dialog)
|
||||
{
|
||||
m_dialog = dialog;
|
||||
}
|
||||
|
||||
// called from ---GUI--- thread
|
||||
std::unordered_set<std::string> NetPlayServer::GetInterfaceSet()
|
||||
{
|
||||
std::unordered_set<std::string> result;
|
||||
auto lst = GetInterfaceListInternal();
|
||||
for (auto list_entry : lst)
|
||||
result.emplace(list_entry.first);
|
||||
return result;
|
||||
}
|
||||
|
||||
// called from ---GUI--- thread
|
||||
std::string NetPlayServer::GetInterfaceHost(const std::string inter)
|
||||
{
|
||||
char buf[16];
|
||||
sprintf(buf, ":%d", GetPort());
|
||||
auto lst = GetInterfaceListInternal();
|
||||
for (const auto& list_entry : lst)
|
||||
{
|
||||
if (list_entry.first == inter)
|
||||
{
|
||||
return list_entry.second + buf;
|
||||
}
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
// called from ---GUI--- thread
|
||||
std::vector<std::pair<std::string, std::string>> NetPlayServer::GetInterfaceListInternal()
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> result;
|
||||
#if defined(_WIN32)
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
// we do this to get the friendly names rather than the BSD ones. ew.
|
||||
if (m_dynamic_store && m_prefs)
|
||||
{
|
||||
CFArrayRef ary = SCNetworkServiceCopyAll((SCPreferencesRef)m_prefs);
|
||||
for (CFIndex i = 0; i < CFArrayGetCount(ary); i++)
|
||||
{
|
||||
SCNetworkServiceRef ifr = (SCNetworkServiceRef)CFArrayGetValueAtIndex(ary, i);
|
||||
std::string name = CFStrToStr(SCNetworkServiceGetName(ifr));
|
||||
CFStringRef key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, SCNetworkServiceGetServiceID(ifr), kSCEntNetIPv4);
|
||||
CFDictionaryRef props = (CFDictionaryRef)SCDynamicStoreCopyValue((SCDynamicStoreRef)m_dynamic_store, key);
|
||||
CFRelease(key);
|
||||
if (!props)
|
||||
continue;
|
||||
CFArrayRef ipary = (CFArrayRef)CFDictionaryGetValue(props, kSCPropNetIPv4Addresses);
|
||||
if (ipary)
|
||||
{
|
||||
for (CFIndex j = 0; j < CFArrayGetCount(ipary); j++)
|
||||
result.emplace_back(std::make_pair(name, CFStrToStr((CFStringRef)CFArrayGetValueAtIndex(ipary, j))));
|
||||
CFRelease(ipary);
|
||||
}
|
||||
}
|
||||
CFRelease(ary);
|
||||
}
|
||||
#elif defined(ANDROID)
|
||||
// Android has no getifaddrs for some stupid reason. If this
|
||||
// functionality ends up actually being used on Android, fix this.
|
||||
#else
|
||||
ifaddrs* ifp;
|
||||
char buf[512];
|
||||
if (getifaddrs(&ifp) != -1)
|
||||
{
|
||||
for (struct ifaddrs* curifp = ifp; curifp; curifp = curifp->ifa_next)
|
||||
{
|
||||
struct sockaddr* sa = curifp->ifa_addr;
|
||||
if (sa->sa_family != AF_INET)
|
||||
continue;
|
||||
struct 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.push_back(std::make_pair("!local!", "127.0.0.1"));
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef USE_UPNP
|
||||
#include <miniwget.h>
|
||||
#include <miniupnpc.h>
|
||||
|
|
|
@ -9,18 +9,20 @@
|
|||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "enet/enet.h"
|
||||
#include "Common/Thread.h"
|
||||
#include "Common/TraversalClient.h"
|
||||
#include "Common/Timer.h"
|
||||
#include "Core/NetPlayProto.h"
|
||||
#include <SFML/Network/Packet.hpp>
|
||||
|
||||
class NetPlayServer
|
||||
class NetPlayUI;
|
||||
|
||||
class NetPlayServer : public TraversalClientClient
|
||||
{
|
||||
public:
|
||||
void ThreadFunc();
|
||||
|
||||
NetPlayServer(const u16 port);
|
||||
NetPlayServer(const u16 port, bool traversal);
|
||||
~NetPlayServer();
|
||||
|
||||
bool ChangeGame(const std::string& game);
|
||||
|
@ -42,6 +44,10 @@ public:
|
|||
|
||||
u16 GetPort();
|
||||
|
||||
void SetNetPlayUI(NetPlayUI* dialog);
|
||||
std::unordered_set<std::string> GetInterfaceSet();
|
||||
std::string GetInterfaceHost(const std::string inter);
|
||||
|
||||
bool is_connected;
|
||||
|
||||
#ifdef USE_UPNP
|
||||
|
@ -71,8 +77,12 @@ private:
|
|||
unsigned int OnConnect(ENetPeer* socket);
|
||||
unsigned int OnDisconnect(Client& player);
|
||||
unsigned int OnData(sf::Packet& packet, Client& player);
|
||||
virtual void OnTraversalStateChanged();
|
||||
virtual void OnConnectReady(ENetAddress addr) {}
|
||||
virtual void OnConnectFailed(u8 reason) {}
|
||||
void UpdatePadMapping();
|
||||
void UpdateWiimoteMapping();
|
||||
std::vector<std::pair<std::string, std::string>> GetInterfaceListInternal();
|
||||
|
||||
NetSettings m_settings;
|
||||
|
||||
|
@ -99,6 +109,8 @@ private:
|
|||
std::thread m_thread;
|
||||
|
||||
ENetHost* m_server;
|
||||
TraversalClient* m_traversal_client;
|
||||
NetPlayUI* m_dialog;
|
||||
|
||||
#ifdef USE_UPNP
|
||||
static void mapPortThread(const u16 port);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <wx/string.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/translation.h>
|
||||
#include <wx/clipbrd.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FifoQueue.h"
|
||||
|
@ -53,6 +54,26 @@ static NetPlayServer* netplay_server = nullptr;
|
|||
static NetPlayClient* netplay_client = nullptr;
|
||||
NetPlayDiag *NetPlayDiag::npd = nullptr;
|
||||
|
||||
|
||||
static wxString FailureReasonStringForHostLabel(int reason)
|
||||
{
|
||||
switch (reason)
|
||||
{
|
||||
case TraversalClient::BadHost:
|
||||
return _("(Error: Bad host)");
|
||||
case TraversalClient::VersionTooOld:
|
||||
return _("(Error: Dolphin too old)");
|
||||
case TraversalClient::ServerForgotAboutUs:
|
||||
return _("(Error: Disconnected)");
|
||||
case TraversalClient::SocketSendError:
|
||||
return _("(Error: Socket)");
|
||||
case TraversalClient::ResendTimeout:
|
||||
return _("(Error: Timeout)");
|
||||
default:
|
||||
return _("(Error: Unknown)");
|
||||
}
|
||||
}
|
||||
|
||||
static std::string BuildGameName(const GameListItem& game)
|
||||
{
|
||||
// Lang needs to be consistent
|
||||
|
@ -93,7 +114,6 @@ NetPlaySetupDiag::NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl*
|
|||
nick_szr->Add(nick_lbl, 0, wxCENTER);
|
||||
nick_szr->Add(m_nickname_text, 0, wxALL, 5);
|
||||
|
||||
|
||||
// tabs
|
||||
wxNotebook* const notebook = new wxNotebook(panel, wxID_ANY);
|
||||
wxPanel* const connect_tab = new wxPanel(notebook, wxID_ANY);
|
||||
|
@ -101,85 +121,91 @@ NetPlaySetupDiag::NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl*
|
|||
wxPanel* const host_tab = new wxPanel(notebook, wxID_ANY);
|
||||
notebook->AddPage(host_tab, _("Host"));
|
||||
|
||||
m_direct_traversal = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(75, -1));
|
||||
m_direct_traversal->Bind(wxEVT_COMMAND_CHOICE_SELECTED, &NetPlaySetupDiag::OnChoice, this);
|
||||
m_direct_traversal->Append(_("Traversal"));
|
||||
m_direct_traversal->Append(_("Direct"));
|
||||
m_direct_traversal->Select(0);
|
||||
|
||||
// connect tab
|
||||
{
|
||||
wxStaticText* const ip_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Address :"));
|
||||
m_ip_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Host Code :"));
|
||||
|
||||
std::string address;
|
||||
netplay_section.Get("Address", &address, "localhost");
|
||||
m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(address));
|
||||
std::string address;
|
||||
netplay_section.Get("HostCode", &address, "00000000");
|
||||
m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(address));
|
||||
|
||||
wxStaticText* const port_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Port :"));
|
||||
m_client_port_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Port :"));
|
||||
|
||||
// string? w/e
|
||||
std::string port;
|
||||
netplay_section.Get("ConnectPort", &port, "2626");
|
||||
m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(port));
|
||||
// string? w/e
|
||||
std::string port;
|
||||
netplay_section.Get("ConnectPort", &port, "2626");
|
||||
m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(port));
|
||||
|
||||
wxButton* const connect_btn = new wxButton(connect_tab, wxID_ANY, _("Connect"));
|
||||
connect_btn->Bind(wxEVT_BUTTON, &NetPlaySetupDiag::OnJoin, this);
|
||||
wxButton* const connect_btn = new wxButton(connect_tab, wxID_ANY, _("Connect"));
|
||||
connect_btn->Bind(wxEVT_BUTTON, &NetPlaySetupDiag::OnJoin, this);
|
||||
|
||||
wxStaticText* const alert_lbl = new wxStaticText(connect_tab, wxID_ANY,
|
||||
_("ALERT:\n\n"
|
||||
"Netplay will only work with the following settings:\n"
|
||||
" - DSP Emulator Engine Must be the same on all computers!\n"
|
||||
" - DSP on Dedicated Thread [OFF]\n"
|
||||
" - Manually set the extensions for each Wiimote\n"
|
||||
"\n"
|
||||
"All players should use the same Dolphin version and settings.\n"
|
||||
"All memory cards must be identical between players or disabled.\n"
|
||||
"Wiimote support is probably terrible. Don't use it.\n"
|
||||
"\n"
|
||||
"The host must have the chosen TCP port open/forwarded!\n"));
|
||||
wxStaticText* const alert_lbl = new wxStaticText(connect_tab, wxID_ANY,
|
||||
_("ALERT:\n\n"
|
||||
"Netplay will only work with the following settings:\n"
|
||||
" - DSP Emulator Engine Must be the same on all computers!\n"
|
||||
" - DSP on Dedicated Thread [OFF]\n"
|
||||
" - Manually set the extensions for each Wiimote\n"
|
||||
"\n"
|
||||
"All players should use the same Dolphin version and settings.\n"
|
||||
"All memory cards must be identical between players or disabled.\n"
|
||||
"Wiimote support is probably terrible. Don't use it.\n"
|
||||
"\n"
|
||||
"If connecting directly host must have the chosen UDP port open/forwarded!\n"));
|
||||
|
||||
wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL);
|
||||
top_szr->Add(ip_lbl, 0, wxCENTER | wxRIGHT, 5);
|
||||
top_szr->Add(m_connect_ip_text, 3);
|
||||
top_szr->Add(port_lbl, 0, wxCENTER | wxRIGHT | wxLEFT, 5);
|
||||
top_szr->Add(m_connect_port_text, 1);
|
||||
wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
wxBoxSizer* const con_szr = new wxBoxSizer(wxVERTICAL);
|
||||
con_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5);
|
||||
con_szr->AddStretchSpacer(1);
|
||||
con_szr->Add(alert_lbl, 0, wxLEFT | wxRIGHT | wxEXPAND, 5);
|
||||
con_szr->AddStretchSpacer(1);
|
||||
con_szr->Add(connect_btn, 0, wxALL | wxALIGN_RIGHT, 5);
|
||||
top_szr->Add(m_ip_lbl, 0, wxCENTER | wxRIGHT, 5);
|
||||
top_szr->Add(m_connect_ip_text, 3);
|
||||
top_szr->Add(m_client_port_lbl, 0, wxCENTER | wxRIGHT | wxLEFT, 5);
|
||||
top_szr->Add(m_connect_port_text, 1);
|
||||
|
||||
connect_tab->SetSizerAndFit(con_szr);
|
||||
wxBoxSizer* const con_szr = new wxBoxSizer(wxVERTICAL);
|
||||
con_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5);
|
||||
con_szr->AddStretchSpacer(1);
|
||||
con_szr->Add(alert_lbl, 0, wxLEFT | wxRIGHT | wxEXPAND, 5);
|
||||
con_szr->AddStretchSpacer(1);
|
||||
con_szr->Add(connect_btn, 0, wxALL | wxALIGN_RIGHT, 5);
|
||||
|
||||
connect_tab->SetSizerAndFit(con_szr);
|
||||
}
|
||||
|
||||
// host tab
|
||||
{
|
||||
wxStaticText* const port_lbl = new wxStaticText(host_tab, wxID_ANY, _("Port :"));
|
||||
m_host_port_lbl = new wxStaticText(host_tab, wxID_ANY, _("Port :"));
|
||||
|
||||
// string? w/e
|
||||
std::string port;
|
||||
netplay_section.Get("HostPort", &port, "2626");
|
||||
m_host_port_text = new wxTextCtrl(host_tab, wxID_ANY, StrToWxStr(port));
|
||||
// string? w/e
|
||||
std::string port;
|
||||
netplay_section.Get("HostPort", &port, "2626");
|
||||
m_host_port_text = new wxTextCtrl(host_tab, wxID_ANY, StrToWxStr(port));
|
||||
|
||||
wxButton* const host_btn = new wxButton(host_tab, wxID_ANY, _("Host"));
|
||||
host_btn->Bind(wxEVT_BUTTON, &NetPlaySetupDiag::OnHost, this);
|
||||
wxButton* const host_btn = new wxButton(host_tab, wxID_ANY, _("Host"));
|
||||
host_btn->Bind(wxEVT_BUTTON, &NetPlaySetupDiag::OnHost, this);
|
||||
|
||||
m_game_lbox = new wxListBox(host_tab, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT);
|
||||
m_game_lbox->Bind(wxEVT_LISTBOX_DCLICK, &NetPlaySetupDiag::OnHost, this);
|
||||
m_game_lbox = new wxListBox(host_tab, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT);
|
||||
m_game_lbox->Bind(wxEVT_LISTBOX_DCLICK, &NetPlaySetupDiag::OnHost, this);
|
||||
|
||||
FillWithGameNames(m_game_lbox, *game_list);
|
||||
FillWithGameNames(m_game_lbox, *game_list);
|
||||
|
||||
wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL);
|
||||
top_szr->Add(port_lbl, 0, wxCENTER | wxRIGHT, 5);
|
||||
top_szr->Add(m_host_port_text, 0);
|
||||
wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL);
|
||||
top_szr->Add(m_host_port_lbl, 0, wxCENTER | wxRIGHT, 5);
|
||||
top_szr->Add(m_host_port_text, 0);
|
||||
#ifdef USE_UPNP
|
||||
m_upnp_chk = new wxCheckBox(host_tab, wxID_ANY, _("Forward port (UPnP)"));
|
||||
top_szr->Add(m_upnp_chk, 0, wxALL | wxALIGN_RIGHT, 5);
|
||||
m_upnp_chk = new wxCheckBox(host_tab, wxID_ANY, _("Forward port (UPnP)"));
|
||||
top_szr->Add(m_upnp_chk, 0, wxALL | wxALIGN_RIGHT, 5);
|
||||
#endif
|
||||
|
||||
wxBoxSizer* const host_szr = new wxBoxSizer(wxVERTICAL);
|
||||
host_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5);
|
||||
host_szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxEXPAND, 5);
|
||||
host_szr->Add(host_btn, 0, wxALL | wxALIGN_RIGHT, 5);
|
||||
wxBoxSizer* const host_szr = new wxBoxSizer(wxVERTICAL);
|
||||
host_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5);
|
||||
host_szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxEXPAND, 5);
|
||||
host_szr->Add(host_btn, 0, wxALL | wxALIGN_RIGHT, 5);
|
||||
|
||||
host_tab->SetSizerAndFit(host_szr);
|
||||
host_tab->SetSizerAndFit(host_szr);
|
||||
}
|
||||
|
||||
// bottom row
|
||||
|
@ -202,6 +228,21 @@ NetPlaySetupDiag::NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl*
|
|||
|
||||
Center();
|
||||
Show();
|
||||
|
||||
// Needs to be done last or it set up the spacing on the page correctly
|
||||
//client tab
|
||||
{
|
||||
m_client_port_lbl->Show(false);
|
||||
m_connect_port_text->Show(false);
|
||||
}
|
||||
|
||||
//server tab
|
||||
{
|
||||
m_host_port_lbl->Show(false);
|
||||
m_host_port_text->Show(false);
|
||||
m_upnp_chk->Show(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NetPlaySetupDiag::~NetPlaySetupDiag()
|
||||
|
@ -212,7 +253,14 @@ NetPlaySetupDiag::~NetPlaySetupDiag()
|
|||
IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay");
|
||||
|
||||
netplay_section.Set("Nickname", WxStrToStr(m_nickname_text->GetValue()));
|
||||
netplay_section.Set("Address", WxStrToStr(m_connect_ip_text->GetValue()));
|
||||
if (m_direct_traversal->GetCurrentSelection() == 1)
|
||||
{
|
||||
netplay_section.Set("Address", WxStrToStr(m_connect_ip_text->GetValue()));
|
||||
}
|
||||
else
|
||||
{
|
||||
netplay_section.Set("HostCode", WxStrToStr(m_connect_ip_text->GetValue()));
|
||||
}
|
||||
netplay_section.Set("ConnectPort", WxStrToStr(m_connect_port_text->GetValue()));
|
||||
netplay_section.Set("HostPort", WxStrToStr(m_host_port_text->GetValue()));
|
||||
|
||||
|
@ -230,7 +278,13 @@ void NetPlaySetupDiag::MakeNetPlayDiag(int port, const std::string &game, bool i
|
|||
else
|
||||
ip = WxStrToStr(m_connect_ip_text->GetValue());
|
||||
|
||||
netplay_client = new NetPlayClient(ip, (u16)port, npd, WxStrToStr(m_nickname_text->GetValue()));
|
||||
bool trav;
|
||||
if (!is_hosting && m_direct_traversal->GetCurrentSelection() == 0)
|
||||
trav = true;
|
||||
else
|
||||
trav = false;
|
||||
|
||||
netplay_client = new NetPlayClient(ip, (u16)port, npd, WxStrToStr(m_nickname_text->GetValue()), trav);
|
||||
if (netplay_client->is_connected)
|
||||
{
|
||||
npd->Show();
|
||||
|
@ -259,9 +313,15 @@ void NetPlaySetupDiag::OnHost(wxCommandEvent&)
|
|||
|
||||
std::string game(WxStrToStr(m_game_lbox->GetStringSelection()));
|
||||
|
||||
bool trav;
|
||||
if (m_direct_traversal->GetCurrentSelection() == 0)
|
||||
trav = true;
|
||||
else
|
||||
trav = false;
|
||||
|
||||
unsigned long port = 0;
|
||||
m_host_port_text->GetValue().ToULong(&port);
|
||||
netplay_server = new NetPlayServer(u16(port));
|
||||
netplay_server = new NetPlayServer(u16(port), trav);
|
||||
netplay_server->ChangeGame(game);
|
||||
netplay_server->AdjustPadBufferSize(INITIAL_PAD_BUFFER_SIZE);
|
||||
if (netplay_server->is_connected)
|
||||
|
@ -270,7 +330,8 @@ void NetPlaySetupDiag::OnHost(wxCommandEvent&)
|
|||
if (m_upnp_chk->GetValue())
|
||||
netplay_server->TryPortmapping(port);
|
||||
#endif
|
||||
MakeNetPlayDiag(port, game, true);
|
||||
MakeNetPlayDiag(netplay_server->GetPort(), game, true);
|
||||
netplay_server->SetNetPlayUI(NetPlayDiag::GetInstance());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -292,17 +353,75 @@ void NetPlaySetupDiag::OnJoin(wxCommandEvent&)
|
|||
MakeNetPlayDiag(port, "", false);
|
||||
}
|
||||
|
||||
void NetPlaySetupDiag::OnChoice(wxCommandEvent& event)
|
||||
{
|
||||
int sel = m_direct_traversal->GetSelection();
|
||||
IniFile inifile;
|
||||
inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini");
|
||||
IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay");
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
//Traversal
|
||||
//client tab
|
||||
{
|
||||
m_ip_lbl->SetLabelText("Host Code: ");
|
||||
|
||||
std::string address;
|
||||
netplay_section.Get("HostCode", &address, "00000000");
|
||||
m_connect_ip_text->SetLabelText(address);
|
||||
|
||||
m_client_port_lbl->Show(false);
|
||||
m_connect_port_text->Show(false);
|
||||
}
|
||||
|
||||
//server tab
|
||||
{
|
||||
m_host_port_lbl->Show(false);
|
||||
m_host_port_text->Show(false);
|
||||
m_upnp_chk->Show(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Direct
|
||||
//client tab
|
||||
{
|
||||
m_ip_lbl->SetLabelText("IP Address :");
|
||||
|
||||
std::string address;
|
||||
netplay_section.Get("Address", &address, "127.0.0.1");
|
||||
m_connect_ip_text->SetLabelText(address);
|
||||
|
||||
m_client_port_lbl->Show(true);
|
||||
m_connect_port_text->Show(true);
|
||||
}
|
||||
|
||||
//server tab
|
||||
{
|
||||
m_host_port_lbl->Show(true);
|
||||
m_host_port_text->Show(true);
|
||||
m_upnp_chk->Show(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetPlaySetupDiag::OnQuit(wxCommandEvent&)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
NetPlayDiag::NetPlayDiag(wxWindow* const parent, const CGameListCtrl* const game_list,
|
||||
const std::string& game, const bool is_hosting)
|
||||
const std::string& game, const bool is_hosting)
|
||||
: wxFrame(parent, wxID_ANY, _("Dolphin NetPlay"))
|
||||
, m_selected_game(game)
|
||||
, m_start_btn(nullptr)
|
||||
, m_game_list(game_list)
|
||||
, m_host_type_choice(nullptr)
|
||||
, m_host_label(nullptr)
|
||||
, m_host_copy_btn(nullptr)
|
||||
, m_host_copy_btn_is_retry(false)
|
||||
, m_is_hosting(is_hosting)
|
||||
{
|
||||
Bind(wxEVT_THREAD, &NetPlayDiag::OnThread, this);
|
||||
|
||||
|
@ -310,10 +429,10 @@ NetPlayDiag::NetPlayDiag(wxWindow* const parent, const CGameListCtrl* const game
|
|||
|
||||
// top crap
|
||||
m_game_btn = new wxButton(panel, wxID_ANY,
|
||||
StrToWxStr(m_selected_game).Prepend(_(" Game : ")),
|
||||
wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
|
||||
StrToWxStr(m_selected_game).Prepend(_(" Game : ")),
|
||||
wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
|
||||
|
||||
if (is_hosting)
|
||||
if (m_is_hosting)
|
||||
m_game_btn->Bind(wxEVT_BUTTON, &NetPlayDiag::OnChangeGame, this);
|
||||
else
|
||||
m_game_btn->Disable();
|
||||
|
@ -343,9 +462,34 @@ NetPlayDiag::NetPlayDiag(wxWindow* const parent, const CGameListCtrl* const game
|
|||
m_player_lbox = new wxListBox(panel, wxID_ANY, wxDefaultPosition, wxSize(256, -1));
|
||||
|
||||
wxStaticBoxSizer* const player_szr = new wxStaticBoxSizer(wxVERTICAL, panel, _("Players"));
|
||||
player_szr->Add(m_player_lbox, 1, wxEXPAND);
|
||||
|
||||
// player list
|
||||
if (is_hosting)
|
||||
if (m_is_hosting && g_TraversalClient)
|
||||
{
|
||||
wxBoxSizer* const host_szr = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_host_type_choice = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(60, -1));
|
||||
m_host_type_choice->Bind(wxEVT_COMMAND_CHOICE_SELECTED, &NetPlayDiag::OnChoice, this);
|
||||
m_host_type_choice->Append(_("ID:"));
|
||||
host_szr->Add(m_host_type_choice);
|
||||
|
||||
m_host_label = new wxStaticText(panel, wxID_ANY, "555.555.555.555:55555", wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE | wxALIGN_LEFT);
|
||||
// Update() should fix this immediately.
|
||||
m_host_label->SetLabel(_(""));
|
||||
host_szr->Add(m_host_label, 1, wxLEFT | wxCENTER, 5);
|
||||
|
||||
m_host_copy_btn = new wxButton(panel, wxID_ANY, _("Copy"));
|
||||
m_host_copy_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &NetPlayDiag::OnCopyIP, this);
|
||||
m_host_copy_btn->Disable();
|
||||
host_szr->Add(m_host_copy_btn, 0, wxLEFT | wxCENTER, 5);
|
||||
player_szr->Add(host_szr, 0, wxEXPAND | wxBOTTOM, 5);
|
||||
m_host_type_choice->Select(0);
|
||||
|
||||
UpdateHostLabel();
|
||||
}
|
||||
|
||||
player_szr->Add(m_player_lbox, 1, wxEXPAND);
|
||||
|
||||
if (m_is_hosting)
|
||||
{
|
||||
m_player_lbox->Bind(wxEVT_LISTBOX, &NetPlayDiag::OnPlayerSelect, this);
|
||||
m_kick_btn = new wxButton(panel, wxID_ANY, _("Kick Player"));
|
||||
|
@ -398,7 +542,7 @@ NetPlayDiag::NetPlayDiag(wxWindow* const parent, const CGameListCtrl* const game
|
|||
panel->SetSizerAndFit(main_szr);
|
||||
|
||||
main_szr->SetSizeHints(this);
|
||||
SetSize(512, 512-128);
|
||||
SetSize(512, 512 - 128);
|
||||
|
||||
Center();
|
||||
}
|
||||
|
@ -531,6 +675,11 @@ void NetPlayDiag::OnQuit(wxCommandEvent&)
|
|||
// update gui
|
||||
void NetPlayDiag::OnThread(wxThreadEvent& event)
|
||||
{
|
||||
if (m_is_hosting && m_host_label && g_TraversalClient)
|
||||
{
|
||||
UpdateHostLabel();
|
||||
}
|
||||
|
||||
// player list
|
||||
m_playerids.clear();
|
||||
std::string tmps;
|
||||
|
@ -563,8 +712,8 @@ void NetPlayDiag::OnThread(wxThreadEvent& event)
|
|||
// flash window in taskbar when someone joins if window isn't active
|
||||
static u8 numPlayers = 1;
|
||||
bool focus = (wxWindow::FindFocus() == this || (wxWindow::FindFocus() != nullptr && wxWindow::FindFocus()->GetParent() == this) ||
|
||||
(wxWindow::FindFocus() != nullptr && wxWindow::FindFocus()->GetParent() != nullptr
|
||||
&& wxWindow::FindFocus()->GetParent()->GetParent() == this));
|
||||
(wxWindow::FindFocus() != nullptr && wxWindow::FindFocus()->GetParent() != nullptr
|
||||
&& wxWindow::FindFocus()->GetParent()->GetParent() == this));
|
||||
if (netplay_server != nullptr && numPlayers < m_playerids.size() && !focus)
|
||||
{
|
||||
RequestUserAttention();
|
||||
|
@ -575,25 +724,25 @@ void NetPlayDiag::OnThread(wxThreadEvent& event)
|
|||
{
|
||||
case NP_GUI_EVT_CHANGE_GAME:
|
||||
// update selected game :/
|
||||
{
|
||||
{
|
||||
m_selected_game.assign(WxStrToStr(event.GetString()));
|
||||
|
||||
wxString button_label = event.GetString();
|
||||
m_game_btn->SetLabel(button_label.Prepend(_(" Game : ")));
|
||||
}
|
||||
break;
|
||||
case NP_GUI_EVT_START_GAME :
|
||||
}
|
||||
break;
|
||||
case NP_GUI_EVT_START_GAME:
|
||||
// client start game :/
|
||||
{
|
||||
{
|
||||
netplay_client->StartGame(FindGame());
|
||||
}
|
||||
break;
|
||||
case NP_GUI_EVT_STOP_GAME :
|
||||
}
|
||||
break;
|
||||
case NP_GUI_EVT_STOP_GAME:
|
||||
// client stop game
|
||||
{
|
||||
{
|
||||
netplay_client->StopGame();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// chat messages
|
||||
|
@ -660,6 +809,98 @@ bool NetPlayDiag::IsRecording()
|
|||
return m_record_chkbox->GetValue();
|
||||
}
|
||||
|
||||
|
||||
void NetPlayDiag::OnCopyIP(wxCommandEvent&)
|
||||
{
|
||||
if (m_host_copy_btn_is_retry)
|
||||
{
|
||||
g_TraversalClient->ReconnectToServer();
|
||||
Update();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wxTheClipboard->Open())
|
||||
{
|
||||
wxTheClipboard->SetData(new wxTextDataObject(m_host_label->GetLabel()));
|
||||
wxTheClipboard->Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetPlayDiag::OnChoice(wxCommandEvent& event)
|
||||
{
|
||||
UpdateHostLabel();
|
||||
}
|
||||
|
||||
|
||||
void NetPlayDiag::UpdateHostLabel()
|
||||
{
|
||||
wxString label = _(" (internal IP)");
|
||||
auto DeLabel = [=](wxString str) {
|
||||
if (str == _("Localhost"))
|
||||
return std::string("!local!");
|
||||
return WxStrToStr(str.Left(str.Len() - label.Len()));
|
||||
};
|
||||
auto EnLabel = [=](std::string str) -> wxString {
|
||||
if (str == "!local!")
|
||||
return _("Localhost");
|
||||
return StrToWxStr(str) + label;
|
||||
};
|
||||
int sel = m_host_type_choice->GetSelection();
|
||||
if (sel == 0)
|
||||
{
|
||||
// the traversal ID
|
||||
switch (g_TraversalClient->m_State)
|
||||
{
|
||||
case TraversalClient::Connecting:
|
||||
m_host_label->SetForegroundColour(*wxLIGHT_GREY);
|
||||
m_host_label->SetLabel("...");
|
||||
m_host_copy_btn->SetLabel(_("Copy"));
|
||||
m_host_copy_btn->Disable();
|
||||
break;
|
||||
case TraversalClient::Connected:
|
||||
m_host_label->SetForegroundColour(*wxBLACK);
|
||||
m_host_label->SetLabel(wxString(g_TraversalClient->m_HostId.data(), g_TraversalClient->m_HostId.size()));
|
||||
m_host_copy_btn->SetLabel(_("Copy"));
|
||||
m_host_copy_btn->Enable();
|
||||
m_host_copy_btn_is_retry = false;
|
||||
break;
|
||||
case TraversalClient::Failure:
|
||||
m_host_label->SetForegroundColour(*wxBLACK);
|
||||
m_host_label->SetLabel(FailureReasonStringForHostLabel(g_TraversalClient->m_FailureReason));
|
||||
m_host_copy_btn->SetLabel(_("Retry"));
|
||||
m_host_copy_btn->Enable();
|
||||
m_host_copy_btn_is_retry = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (sel != wxNOT_FOUND) // wxNOT_FOUND shouldn't generally happen
|
||||
{
|
||||
m_host_label->SetForegroundColour(*wxBLACK);
|
||||
m_host_label->SetLabel(netplay_server->GetInterfaceHost(DeLabel(m_host_type_choice->GetString(sel))));
|
||||
m_host_copy_btn->SetLabel(_("Copy"));
|
||||
m_host_copy_btn->Enable();
|
||||
m_host_copy_btn_is_retry = false;
|
||||
}
|
||||
|
||||
auto set = netplay_server->GetInterfaceSet();
|
||||
for (const std::string& iface : set)
|
||||
{
|
||||
wxString wxIface = EnLabel(iface);
|
||||
if (m_host_type_choice->FindString(wxIface) == wxNOT_FOUND)
|
||||
m_host_type_choice->Append(wxIface);
|
||||
}
|
||||
for (unsigned i = 1, count = m_host_type_choice->GetCount(); i != count; i++)
|
||||
{
|
||||
if (set.find(DeLabel(m_host_type_choice->GetString(i))) == set.end())
|
||||
{
|
||||
m_host_type_choice->Delete(i);
|
||||
i--;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChangeGameDiag::ChangeGameDiag(wxWindow* const parent, const CGameListCtrl* const game_list, wxString& game_name)
|
||||
: wxDialog(parent, wxID_ANY, _("Change Game"))
|
||||
, m_game_name(game_name)
|
||||
|
@ -728,16 +969,16 @@ PadMapDiag::PadMapDiag(wxWindow* const parent, PadMapping map[], PadMapping wiim
|
|||
v_szr->Add(new wxStaticText(this, wxID_ANY, (wxString(_("Wiimote ")) + (wxChar)('0' + i))),
|
||||
1, wxALIGN_CENTER_HORIZONTAL);
|
||||
|
||||
m_map_cbox[i+4] = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, player_names);
|
||||
m_map_cbox[i+4]->Bind(wxEVT_CHOICE, &PadMapDiag::OnAdjust, this);
|
||||
m_map_cbox[i + 4] = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, player_names);
|
||||
m_map_cbox[i + 4]->Bind(wxEVT_CHOICE, &PadMapDiag::OnAdjust, this);
|
||||
if (m_wiimapping[i] == -1)
|
||||
m_map_cbox[i+4]->Select(0);
|
||||
m_map_cbox[i + 4]->Select(0);
|
||||
else
|
||||
for (unsigned int j = 0; j < m_player_list.size(); j++)
|
||||
if (m_wiimapping[i] == m_player_list[j]->pid)
|
||||
m_map_cbox[i+4]->Select(j + 1);
|
||||
m_map_cbox[i + 4]->Select(j + 1);
|
||||
|
||||
v_szr->Add(m_map_cbox[i+4], 1);
|
||||
v_szr->Add(m_map_cbox[i + 4], 1);
|
||||
|
||||
h_szr->Add(v_szr, 1, wxTOP | wxEXPAND, 20);
|
||||
h_szr->AddSpacer(10);
|
||||
|
@ -763,7 +1004,7 @@ void PadMapDiag::OnAdjust(wxCommandEvent& event)
|
|||
else
|
||||
m_mapping[i] = -1;
|
||||
|
||||
player_idx = m_map_cbox[i+4]->GetSelection();
|
||||
player_idx = m_map_cbox[i + 4]->GetSelection();
|
||||
if (player_idx > 0)
|
||||
m_wiimapping[i] = m_player_list[player_idx - 1]->pid;
|
||||
else
|
||||
|
|
|
@ -42,10 +42,16 @@ private:
|
|||
|
||||
void MakeNetPlayDiag(int port, const std::string &game, bool is_hosting);
|
||||
|
||||
wxTextCtrl* m_nickname_text;
|
||||
wxTextCtrl* m_host_port_text;
|
||||
wxTextCtrl* m_connect_port_text;
|
||||
wxTextCtrl* m_connect_ip_text;
|
||||
void OnChoice(wxCommandEvent& event);
|
||||
|
||||
wxStaticText* m_ip_lbl;
|
||||
wxStaticText* m_client_port_lbl;
|
||||
wxTextCtrl* m_nickname_text;
|
||||
wxStaticText* m_host_port_lbl;
|
||||
wxTextCtrl* m_host_port_text;
|
||||
wxTextCtrl* m_connect_port_text;
|
||||
wxTextCtrl* m_connect_ip_text;
|
||||
wxChoice* m_direct_traversal;
|
||||
|
||||
wxListBox* m_game_lbox;
|
||||
#ifdef USE_UPNP
|
||||
|
@ -93,16 +99,25 @@ private:
|
|||
void GetNetSettings(NetSettings &settings);
|
||||
std::string FindGame();
|
||||
|
||||
wxListBox* m_player_lbox;
|
||||
wxTextCtrl* m_chat_text;
|
||||
wxTextCtrl* m_chat_msg_text;
|
||||
wxCheckBox* m_memcard_write;
|
||||
wxCheckBox* m_record_chkbox;
|
||||
void OnCopyIP(wxCommandEvent&);
|
||||
void OnChoice(wxCommandEvent& event);
|
||||
void UpdateHostLabel();
|
||||
|
||||
std::string m_selected_game;
|
||||
wxButton* m_game_btn;
|
||||
wxButton* m_start_btn;
|
||||
wxButton* m_kick_btn;
|
||||
wxListBox* m_player_lbox;
|
||||
wxTextCtrl* m_chat_text;
|
||||
wxTextCtrl* m_chat_msg_text;
|
||||
wxCheckBox* m_memcard_write;
|
||||
wxCheckBox* m_record_chkbox;
|
||||
|
||||
std::string m_selected_game;
|
||||
wxButton* m_game_btn;
|
||||
wxButton* m_start_btn;
|
||||
wxButton* m_kick_btn;
|
||||
wxStaticText* m_host_label;
|
||||
wxChoice* m_host_type_choice;
|
||||
wxButton* m_host_copy_btn;
|
||||
bool m_host_copy_btn_is_retry;
|
||||
bool m_is_hosting;
|
||||
|
||||
std::vector<int> m_playerids;
|
||||
|
||||
|
|
Loading…
Reference in New Issue