flesh out LAN discovery UI
This commit is contained in:
parent
5153b17dac
commit
db7cee7f2c
|
@ -20,7 +20,6 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <map>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef __WIN32__
|
#ifdef __WIN32__
|
||||||
|
@ -50,6 +49,8 @@
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QInputDialog>
|
||||||
|
|
||||||
#include "LAN.h"
|
#include "LAN.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
@ -61,7 +62,8 @@
|
||||||
|
|
||||||
|
|
||||||
extern EmuThread* emuThread;
|
extern EmuThread* emuThread;
|
||||||
LANDialog* lanDlg;
|
LANStartClientDialog* lanClientDlg = nullptr;
|
||||||
|
LANDialog* lanDlg = nullptr;
|
||||||
|
|
||||||
|
|
||||||
LANStartHostDialog::LANStartHostDialog(QWidget* parent) : QDialog(parent), ui(new Ui::LANStartHostDialog)
|
LANStartHostDialog::LANStartHostDialog(QWidget* parent) : QDialog(parent), ui(new Ui::LANStartHostDialog)
|
||||||
|
@ -102,36 +104,111 @@ LANStartClientDialog::LANStartClientDialog(QWidget* parent) : QDialog(parent), u
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
|
QStandardItemModel* model = new QStandardItemModel();
|
||||||
|
ui->tvAvailableGames->setModel(model);
|
||||||
|
const QStringList listheader = {"Name", "Players", "Status"};
|
||||||
|
model->setHorizontalHeaderLabels(listheader);
|
||||||
|
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Ok)->setText("Connect");
|
||||||
|
|
||||||
|
QPushButton* btn = ui->buttonBox->addButton("Direct connect...", QDialogButtonBox::ActionRole);
|
||||||
|
connect(btn, SIGNAL(clicked()), this, SLOT(onDirectConnect()));
|
||||||
|
|
||||||
|
connect(this, &LANStartClientDialog::sgUpdateDiscoveryList, this, &LANStartClientDialog::doUpdateDiscoveryList);
|
||||||
|
|
||||||
|
lanClientDlg = this;
|
||||||
|
LAN::StartDiscovery();
|
||||||
}
|
}
|
||||||
|
|
||||||
LANStartClientDialog::~LANStartClientDialog()
|
LANStartClientDialog::~LANStartClientDialog()
|
||||||
{
|
{
|
||||||
|
lanClientDlg = nullptr;
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LANStartClientDialog::onDirectConnect()
|
||||||
|
{
|
||||||
|
QString host = QInputDialog::getText(this, "Direct connect", "Host address:");
|
||||||
|
if (host.isEmpty()) return;
|
||||||
|
|
||||||
|
printf("dicks: %s\n", host.toStdString().c_str());
|
||||||
|
//QDialog::done(QDialog::Accepted);
|
||||||
|
}
|
||||||
|
|
||||||
void LANStartClientDialog::done(int r)
|
void LANStartClientDialog::done(int r)
|
||||||
{
|
{
|
||||||
if (r == QDialog::Accepted)
|
if (r == QDialog::Accepted)
|
||||||
{
|
{
|
||||||
std::string player = ui->txtPlayerName->text().toStdString();
|
std::string player = ui->txtPlayerName->text().toStdString();
|
||||||
std::string host = ui->txtIPAddress->text().toStdString();
|
//std::string host = ui->txtIPAddress->text().toStdString();
|
||||||
|
|
||||||
// TODO validate input!!
|
// TODO validate input!!
|
||||||
|
|
||||||
lanDlg = LANDialog::openDlg(parentWidget());
|
lanDlg = LANDialog::openDlg(parentWidget());
|
||||||
|
|
||||||
LAN::StartClient(player.c_str(), host.c_str());
|
//LAN::StartClient(player.c_str(), host.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TEST!!
|
// TEST!!
|
||||||
printf("borp\n");
|
printf("borp\n");
|
||||||
LAN::StartDiscovery();
|
//LAN::StartDiscovery();
|
||||||
}
|
}
|
||||||
|
|
||||||
QDialog::done(r);
|
QDialog::done(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LANStartClientDialog::updateDiscoveryList()
|
||||||
|
{
|
||||||
|
emit sgUpdateDiscoveryList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LANStartClientDialog::doUpdateDiscoveryList()
|
||||||
|
{
|
||||||
|
LAN::DiscoveryMutex.lock();
|
||||||
|
|
||||||
|
QStandardItemModel* model = (QStandardItemModel*)ui->tvAvailableGames->model();
|
||||||
|
int curcount = model->rowCount();
|
||||||
|
int newcount = LAN::DiscoveryList.size();
|
||||||
|
if (curcount > newcount)
|
||||||
|
{
|
||||||
|
model->removeRows(newcount, curcount-newcount);
|
||||||
|
}
|
||||||
|
else if (curcount < newcount)
|
||||||
|
{
|
||||||
|
for (int i = curcount; i < newcount; i++)
|
||||||
|
{
|
||||||
|
QList<QStandardItem*> row;
|
||||||
|
row.append(new QStandardItem());
|
||||||
|
row.append(new QStandardItem());
|
||||||
|
row.append(new QStandardItem());
|
||||||
|
model->appendRow(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (const auto& [key, data] : LAN::DiscoveryList)
|
||||||
|
{
|
||||||
|
model->item(i, 0)->setText(data.SessionName);
|
||||||
|
|
||||||
|
QString plcount = QString("%0/%1").arg(data.NumPlayers).arg(data.MaxPlayers);
|
||||||
|
model->item(i, 1)->setText(plcount);
|
||||||
|
|
||||||
|
QString status;
|
||||||
|
switch (data.Status)
|
||||||
|
{
|
||||||
|
case 0: status = "Idle"; break;
|
||||||
|
case 1: status = "Playing"; break;
|
||||||
|
}
|
||||||
|
model->item(i, 2)->setText(status);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
LAN::DiscoveryMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
LANDialog::LANDialog(QWidget* parent) : QDialog(parent), ui(new Ui::LANDialog)
|
LANDialog::LANDialog(QWidget* parent) : QDialog(parent), ui(new Ui::LANDialog)
|
||||||
{
|
{
|
||||||
|
@ -211,17 +288,6 @@ const u32 kPacketMagic = 0x4946494E; // NIFI
|
||||||
|
|
||||||
const u32 kProtocolVersion = 1;
|
const u32 kProtocolVersion = 1;
|
||||||
|
|
||||||
struct DiscoveryData
|
|
||||||
{
|
|
||||||
u32 Magic;
|
|
||||||
u32 Version;
|
|
||||||
u32 Tick;
|
|
||||||
char SessionName[64];
|
|
||||||
u8 NumPlayers;
|
|
||||||
u8 MaxPlayers;
|
|
||||||
u8 Status; // 0=idle 1=playing
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MPPacketHeader
|
struct MPPacketHeader
|
||||||
{
|
{
|
||||||
u32 Magic;
|
u32 Magic;
|
||||||
|
@ -237,6 +303,7 @@ const int kLANPort = 7064;
|
||||||
socket_t DiscoverySocket;
|
socket_t DiscoverySocket;
|
||||||
u32 DiscoveryLastTick;
|
u32 DiscoveryLastTick;
|
||||||
std::map<u32, DiscoveryData> DiscoveryList;
|
std::map<u32, DiscoveryData> DiscoveryList;
|
||||||
|
QMutex DiscoveryMutex;
|
||||||
|
|
||||||
bool Active;
|
bool Active;
|
||||||
bool IsHost;
|
bool IsHost;
|
||||||
|
@ -315,7 +382,7 @@ void DeInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void StartDiscovery()
|
bool StartDiscovery()
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
@ -323,7 +390,7 @@ void StartDiscovery()
|
||||||
if (DiscoverySocket < 0)
|
if (DiscoverySocket < 0)
|
||||||
{
|
{
|
||||||
DiscoverySocket = INVALID_SOCKET;
|
DiscoverySocket = INVALID_SOCKET;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sockaddr_in_t saddr;
|
sockaddr_in_t saddr;
|
||||||
|
@ -336,7 +403,7 @@ void StartDiscovery()
|
||||||
{
|
{
|
||||||
closesocket(DiscoverySocket);
|
closesocket(DiscoverySocket);
|
||||||
DiscoverySocket = INVALID_SOCKET;
|
DiscoverySocket = INVALID_SOCKET;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int opt_true = 1;
|
int opt_true = 1;
|
||||||
|
@ -345,16 +412,29 @@ void StartDiscovery()
|
||||||
{
|
{
|
||||||
closesocket(DiscoverySocket);
|
closesocket(DiscoverySocket);
|
||||||
DiscoverySocket = INVALID_SOCKET;
|
DiscoverySocket = INVALID_SOCKET;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
printf("startdisco\n");
|
|
||||||
DiscoveryLastTick = SDL_GetTicks();
|
DiscoveryLastTick = SDL_GetTicks();
|
||||||
DiscoveryList.clear();
|
DiscoveryList.clear();
|
||||||
|
|
||||||
Active = true;
|
Active = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartHost(const char* playername, int numplayers)
|
void EndDiscovery()
|
||||||
|
{
|
||||||
|
if (DiscoverySocket != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
closesocket(DiscoverySocket);
|
||||||
|
DiscoverySocket = INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsHost)
|
||||||
|
Active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StartHost(const char* playername, int numplayers)
|
||||||
{
|
{
|
||||||
ENetAddress addr;
|
ENetAddress addr;
|
||||||
addr.host = ENET_HOST_ANY;
|
addr.host = ENET_HOST_ANY;
|
||||||
|
@ -363,9 +443,7 @@ void StartHost(const char* playername, int numplayers)
|
||||||
Host = enet_host_create(&addr, 16, 2, 0, 0);
|
Host = enet_host_create(&addr, 16, 2, 0, 0);
|
||||||
if (!Host)
|
if (!Host)
|
||||||
{
|
{
|
||||||
// TODO handle this gracefully
|
return false;
|
||||||
printf("host shat itself :(\n");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Player* player = &Players[0];
|
Player* player = &Players[0];
|
||||||
|
@ -388,28 +466,26 @@ void StartHost(const char* playername, int numplayers)
|
||||||
lanDlg->updatePlayerList(Players, NumPlayers);
|
lanDlg->updatePlayerList(Players, NumPlayers);
|
||||||
|
|
||||||
StartDiscovery();
|
StartDiscovery();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartClient(const char* playername, const char* host)
|
bool StartClient(const char* playername, const char* host)
|
||||||
{
|
{
|
||||||
Host = enet_host_create(nullptr, 16, 2, 0, 0);
|
Host = enet_host_create(nullptr, 16, 2, 0, 0);
|
||||||
if (!Host)
|
if (!Host)
|
||||||
{
|
{
|
||||||
// TODO handle this gracefully
|
return false;
|
||||||
printf("client shat itself :(\n");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("client created, connecting (%s, %s:%d)\n", playername, host, kLANPort);
|
|
||||||
|
|
||||||
ENetAddress addr;
|
ENetAddress addr;
|
||||||
enet_address_set_host(&addr, host);
|
enet_address_set_host(&addr, host);
|
||||||
addr.port = kLANPort;
|
addr.port = kLANPort;
|
||||||
ENetPeer* peer = enet_host_connect(Host, &addr, 2, 0);
|
ENetPeer* peer = enet_host_connect(Host, &addr, 2, 0);
|
||||||
if (!peer)
|
if (!peer)
|
||||||
{
|
{
|
||||||
printf("connect shat itself :(\n");
|
enet_host_destroy(Host);
|
||||||
return;
|
Host = nullptr;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ENetEvent event;
|
ENetEvent event;
|
||||||
|
@ -418,16 +494,16 @@ void StartClient(const char* playername, const char* host)
|
||||||
{
|
{
|
||||||
if (event.type == ENET_EVENT_TYPE_CONNECT)
|
if (event.type == ENET_EVENT_TYPE_CONNECT)
|
||||||
{
|
{
|
||||||
printf("connected!\n");
|
|
||||||
conn = true;
|
conn = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!conn)
|
if (!conn)
|
||||||
{
|
{
|
||||||
printf("connection failed\n");
|
|
||||||
enet_peer_reset(peer);
|
enet_peer_reset(peer);
|
||||||
return;
|
enet_host_destroy(Host);
|
||||||
|
Host = nullptr;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player* player = &MyPlayer;
|
Player* player = &MyPlayer;
|
||||||
|
@ -442,6 +518,7 @@ void StartClient(const char* playername, const char* host)
|
||||||
|
|
||||||
Active = true;
|
Active = true;
|
||||||
IsHost = false;
|
IsHost = false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -480,6 +557,8 @@ void ProcessDiscovery()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
DiscoveryMutex.lock();
|
||||||
|
|
||||||
// listen for LAN sessions
|
// listen for LAN sessions
|
||||||
|
|
||||||
fd_set fd;
|
fd_set fd;
|
||||||
|
@ -503,6 +582,13 @@ void ProcessDiscovery()
|
||||||
if (beacon.NumPlayers > beacon.MaxPlayers) continue;
|
if (beacon.NumPlayers > beacon.MaxPlayers) continue;
|
||||||
|
|
||||||
u32 key = ntohl(raddr.sin_addr.s_addr);
|
u32 key = ntohl(raddr.sin_addr.s_addr);
|
||||||
|
|
||||||
|
if (DiscoveryList.find(key) != DiscoveryList.end())
|
||||||
|
{
|
||||||
|
if (beacon.Tick <= DiscoveryList[key].Tick)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
beacon.Magic = tick;
|
beacon.Magic = tick;
|
||||||
DiscoveryList[key] = beacon;
|
DiscoveryList[key] = beacon;
|
||||||
}
|
}
|
||||||
|
@ -524,11 +610,12 @@ void ProcessDiscovery()
|
||||||
DiscoveryList.erase(key);
|
DiscoveryList.erase(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& [key, data] : DiscoveryList)
|
DiscoveryMutex.unlock();
|
||||||
{
|
|
||||||
printf("DISCOVERY: %d.%d.%d.%d\n", key>>24, (key>>16)&0xFF, (key>>8)&0xFF, key&0xFF);
|
// update the list in the connect dialog if needed
|
||||||
printf("- game: %s, %d/%d players\n", data.SessionName, data.NumPlayers, data.MaxPlayers);
|
|
||||||
}
|
if (lanClientDlg)
|
||||||
|
lanClientDlg->updateDiscoveryList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
#define LAN_H
|
#define LAN_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <map>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#include <QMutex>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
@ -33,6 +35,7 @@ class LANDialog;
|
||||||
|
|
||||||
namespace LAN
|
namespace LAN
|
||||||
{
|
{
|
||||||
|
|
||||||
struct Player
|
struct Player
|
||||||
{
|
{
|
||||||
int ID;
|
int ID;
|
||||||
|
@ -40,6 +43,18 @@ struct Player
|
||||||
int Status; // 0=no player 1=normal 2=host 3=connecting
|
int Status; // 0=no player 1=normal 2=host 3=connecting
|
||||||
u32 Address;
|
u32 Address;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DiscoveryData
|
||||||
|
{
|
||||||
|
u32 Magic;
|
||||||
|
u32 Version;
|
||||||
|
u32 Tick;
|
||||||
|
char SessionName[64];
|
||||||
|
u8 NumPlayers;
|
||||||
|
u8 MaxPlayers;
|
||||||
|
u8 Status; // 0=idle 1=playing
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class LANStartHostDialog : public QDialog
|
class LANStartHostDialog : public QDialog
|
||||||
|
@ -79,9 +94,17 @@ public:
|
||||||
return dlg;
|
return dlg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateDiscoveryList();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sgUpdateDiscoveryList();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
void onDirectConnect();
|
||||||
void done(int r);
|
void done(int r);
|
||||||
|
|
||||||
|
void doUpdateDiscoveryList();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::LANStartClientDialog* ui;
|
Ui::LANStartClientDialog* ui;
|
||||||
};
|
};
|
||||||
|
@ -120,12 +143,16 @@ namespace LAN
|
||||||
|
|
||||||
extern bool Active;
|
extern bool Active;
|
||||||
|
|
||||||
|
extern std::map<u32, DiscoveryData> DiscoveryList;
|
||||||
|
extern QMutex DiscoveryMutex;
|
||||||
|
|
||||||
bool Init();
|
bool Init();
|
||||||
void DeInit();
|
void DeInit();
|
||||||
|
|
||||||
void StartDiscovery();
|
bool StartDiscovery();
|
||||||
void StartHost(const char* player, int numplayers);
|
void EndDiscovery();
|
||||||
void StartClient(const char* player, const char* host);
|
bool StartHost(const char* player, int numplayers);
|
||||||
|
bool StartClient(const char* player, const char* host);
|
||||||
|
|
||||||
void ProcessFrame();
|
void ProcessFrame();
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>400</width>
|
<width>547</width>
|
||||||
<height>229</height>
|
<height>409</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
@ -20,33 +20,49 @@
|
||||||
<string>Join LAN game - melonDS</string>
|
<string>Join LAN game - melonDS</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<property name="sizeConstraint">
|
|
||||||
<enum>QLayout::SetFixedSize</enum>
|
|
||||||
</property>
|
|
||||||
<item>
|
<item>
|
||||||
<layout class="QFormLayout" name="formLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item row="0" column="0">
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Player name:</string>
|
<string>Player name:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item>
|
||||||
<widget class="QLineEdit" name="txtPlayerName"/>
|
<widget class="QLineEdit" name="txtPlayerName">
|
||||||
</item>
|
<property name="sizePolicy">
|
||||||
<item row="1" column="0">
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
<widget class="QLabel" name="label_3">
|
<horstretch>0</horstretch>
|
||||||
<property name="text">
|
<verstretch>0</verstretch>
|
||||||
<string>Host address:</string>
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>150</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item>
|
||||||
<widget class="QLineEdit" name="txtIPAddress"/>
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeView" name="tvAvailableGames"/>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|
Loading…
Reference in New Issue